Code Golf: Movement in 3 Dimensions - language-agnostic

Assuming a 3 dimensional irregular matrix where y = 1.5(x) and z = .5(y).
Further assuming an object starts at 0,0,0 and must move positively in at least two dimensions, and must move in all three dimensions (x+1, y+1, z-1 is okay, x+1, y+1, z=z is not). It may move any number of "spaces", but must move the same number in all directions.
The object is allowed to wraparound (x(max +1) = x(0)).
Move said object from its starting position to (0, max(y), .5(max(z))) For z, round up for fractions (end point in 4, 6, 3 matrix becomes 0, 6, 2)
Input is an Integer (X).
Output is the list of moves you would make (extra credit for showing the number of spaces you moved)
Sample Input/Output:
X = 4
Y = 6 //(4 * 1.5)
Z = 3 // 6 / 2
0, 0, 0 //Start
2, 5, 2 // (+2, -2, +2)
1, 2, 2 // (+4, +4, +4)
3, 4, 0 // (+2, +2, -2)
1, 6, 2 // (-2, +2, +2)
3, 3, 3 // (-3, -3, -3)
1, 5, 1 // (-2, +2, -2)
0, 6, 2 // (-1, +1, -1)
7 Moves.

Lua, 68 Characters
The long version below always solves the problem with one move by searching for the first all positive move that will solve problem.
x=...
y,z=x*3/2,x*3/4
a,b,c=0,y,math.ceil(z/2)
x,y,z=x+1,y+1,z+1
for i=1,math.huge do
if (x*i)%y==b and (x*i)%z==c then x=x*i break end
end
print("0,0,0\n0,"..b..","..c.."//+"..x..",+"..x..",+"..x.."\n1 move.")
Output for x = 12:
0,0,0
0,18,5//+455,+455,+455
1 move.
Output for x = 1000:
0,0,0
0,1500,375//+557424868,+557424868,+557424868
1 move.
Seems like the search could be replaced with some simple algebraic equation. But why stop there? Rules are easier to bend in golfing then doing the actual work.
So, assuming that there is always a single 1 move answer, and that I do not have to disclose the "number of spaces you moved", here is the 68 character golfed answer:
x=...print("0,0,0\n0,"..(x*3/2)..","..math.ceil(x*3/8).."\n1 move.")

Mathematica - Not Golfed
Just to see if we can get the ball rolling
... and trying to understand the problem ....
f[x_] := (
(* Init code *)
xmax = x;
ymax = 3 Round[xmax]/2;
zmax = Round[ymax]/2;
xobj = 0;
yobj = ymax;
zobj = Ceiling[zmax/2];
p = Join[Permutations[{1, 1, -1}], {{1, 1, 1}}];
Print["X = ", xmax, "\nY = ", ymax, "\nZ = ", zmax];
(* Loop *)
i = 0;
pos = {0, 0, 0};
k = "Start";
While[
(npos= {Mod[pos[[1]], xmax+1], Mod[pos[[2]], ymax+1], Mod[pos[[3]], zmax+1]})
!= {xobj, yobj, zobj},
i++;
Print[npos, " // ", k];
pos= npos+ (k= RandomInteger[{1,xmax}] p[[RandomInteger[{1, Length[p]}]]]);
];
Print[npos, " // ", k];
Print[i, " Moves"];
);
Invoke with
f[4]
Sample Output
X = 4
Y = 6
Z = 3
{0,0,0} // Start
{3,4,3} // {3,-3,3}
{0,0,2} // {-3,3,3}
{2,3,1} // {-3,3,3}
{0,6,2} // {3,3,-3}
4 Moves
Not sure if I'm following the rules ...

Related

I tried 'interp2' to measure the intensity of a line in octave but I have a method error, any suggestions

imshow(matrix(:,:,1))
%identify axes
[x y] = ginput(2);
% preallocate matrices
cog = zeros(size(matrix,3),1);
%cog
% loop start
for i = 1:size(maytrix,3)
I = matrix(:,:,i);
%n = ceil(norm([diff(x), diff(y)])); % A rough estimation of number of points
test = interp2(I, 2, linspace(x(1), x(2),n), linspace(y(1), y(2),n));
%test = round(test);
cog(i) = sum((1:length(test)).*test')/sum(test);
% loop end
end
scog = (cog - min(cog)) / (max(cog) - min(cog));
Here's a toy example to get you started.
% Create a 100x100x100 3D matrix with a certain pattern
% Smooth pattern:
matrix = [1 : 100] .' * [1 : 100];
matrix = matrix(:) * [1 : 100];
matrix = reshape( matrix, 100, 100, 100 );
% Alternatively, try a random matrix:
%matrix = randn(100,100,100);
Endpoints = randi( [1, 100], [3, 2] ); % Randomly get 2 3D points within matrix
Numpoints = max( abs( diff( Endpoints, 1, 2 ) ) ); % Choose width of widest dimension
% Create a line in 3D space (containing N points) going from one Endpoint to the other.
Linepoints = [ linspace( Endpoints(1, 1), Endpoints(1, 2), Numpoints );
linspace( Endpoints(2, 1), Endpoints(2, 2), Numpoints );
linspace( Endpoints(3, 1), Endpoints(3, 2), Numpoints ); ];
InterpolatedIntensities = interp3( 1:100, 1:100, 1:100, matrix, Linepoints(1, :), Linepoints(2, :), Linepoints(3, :) );
plot( InterpolatedIntensities );

How to plot Iterations in Julia

I coded a function picircle() that estimates pi.
Now I would like to plot this function for N values.
function Plotpi()
p = 100 # precision of π
N = 5
for i in 1:N
picircle(p)
end
end
3.2238805970149254
3.044776119402985
3.1641791044776117
3.1243781094527363
3.084577114427861
Now I am not sure how to plot the function, I tried plot(PP()) but it didn't work
Here I defined picircle:
function picircle(n)
n = n
L = 2n+1
x = range(-1, 1, length=L)
y = rand(L)
center = (0,0)
radius = 1
n_in_circle = 0
for i in 1:L
if norm((x[i], y[i]) .- center) < radius
n_in_circle += 1
end
end
println(4 * n_in_circle / L)
end
Your problem is that your functions don't actually return anything:
julia> x = Plotpi()
3.263681592039801
3.0646766169154227
2.845771144278607
3.18407960199005
3.044776119402985
julia> x
julia> typeof(x)
Nothing
The numbers you see are just printed to the REPL, and print doesn't return any value:
julia> x = print(5)
5
julia> typeof(x)
Nothing
So you probably just want to change your function so that it returns what you want to plot:
julia> function picircle(n)
n = n
L = 2n+1
x = range(-1, 1, length=L)
y = rand(L)
center = (0,0)
radius = 1
n_in_circle = 0
for i in 1:L
if norm((x[i], y[i]) .- center) < radius
n_in_circle += 1
end
end
4 * n_in_circle / L
end
Then:
julia> x = picircle(100)
3.263681592039801
julia> x
3.263681592039801
So now the value of the function is actually returned (rather than just printed to the console). You don't really need a separate function if you just want to do this multiple times and plot the results, a comprehension will do. Here's an example comparing the variability of the estimate with 100 draws vs 50 draws:
julia> using Plots
julia> histogram([picircle(100) for _ ∈ 1:1_000], label = "100 draws", alpha = 0.5)
julia> histogram!([picircle(20) for _ ∈ 1:1_000], label = "20 draws", alpha = 0.5)

How to find binary representation for n'th Fibonacci number

Its my first post here, so if I commit some mistake please let me know.
I have been given a assignment, and a part of it requires the binary representation of n'th Fibonacci number.
Constraints-
) C++ has to be used as prog. language.
) n'th fib. number has to be calculated in lg(n) time.
I have a function but it works on integers. But the maximum value for which I have to do calculations is about 10^6. So, I am badly stuck here.
Whatever I know, I can't apply in this scenario, because I can generate n'th fib. using strings but that will have linear time complexity.
following is the function,
void multiply(long int F[2][2], long int M[2][2]);
void power(long int F[2][2], long int n);
// Function to Calculate n'th fibonacci in log(n) time
long int fib(long int n)
{
long int F[2][2] = {{1,1},{1,0}};
if(n == 0)
return 0;
power(F, n-1);
return F[0][0];
}
void power(long int F[2][2], long int n)
{
if( n == 0 || n == 1)
return;
long int M[2][2] = {{1,1},{1,0}};
power(F, n/2);
multiply(F, F);
if( n%2 != 0 )
multiply(F, M);
}
void multiply(long int F[2][2], long int M[2][2])
{
long int x = (F[0][0]*M[0][0])%mod + (F[0][1]*M[1][0])%mod;
long int y = (F[0][0]*M[0][1])%mod + (F[0][1]*M[1][1])%mod;
long int z = (F[1][0]*M[0][0])%mod + (F[1][1]*M[1][0])%mod;
long int w = (F[1][0]*M[0][1])%mod + (F[1][1]*M[1][1])%mod;
F[0][0] = x;
F[0][1] = y;
F[1][0] = z;
F[1][1] = w;
}
int main(){
int n; cin >> n; cout << fib(n)<<endl; getchar();
}
As it can be seen, only predefined data types can be used in this function.
Since this is homework, I'll only give you little hints.
The two problems are unrelated, so you need two methods: toBinary and fib. toBinary (fib (n)); would be your solution.
For solving the toBinary part, division and modulo are useful and can be called recursively.
If you calculate fib (n) as fib (n-1) + fib (n-2), there is a trap to step into, that when you calculate fib (n-1) as fib (n-2) + fib (n-3), you end up calculating fib (n-2) twice, fib (n-3) three times and so on.
Instead, you should start from (0 + 1) and step upwards, passing already calculated forward.
After a short test, I see how fast the Fibonacci numbers are growing. Do you have access to Ints of arbitrary size, or are you expected to use preallocated arrays?
Then you would need an add method, which takes the lower and the higher number as array of Integers or Booleans, and creates the sum in the lower array, which then becomes the upper array.
update:
Since you solved the problem, I feel free to post my solution for reference, written in Scala:
import annotation._
/**
add two arrays recursively. carry the position pos and the overrun
overrun=0 = 1 0 1 0 1
Sum low | next | Sum
0 1 | overrun | %2
high 0| 0 1 1 2 | 0 0 0 1 | 0 1 1 0
1| 1 2 2 3 | 0 1 1 1 | 1 0 0 1
*/
#tailrec
def add (low: Array[Int], high: Array[Int], pos: Int = 0, overrun: Int = 0): Array[Int] = {
if (pos == higher.size) {
if (overrun == 0) low else sys.error ("overrun!")
} else {
val sum = low (pos) + high (pos) + overrun
low (pos) = (sum % 2)
add (low, high, pos + 1, if (sum > 1) 1 else 0)
}
}
/** call cnt (example: 5) steps of
fib (5, 0, 1),
fib (4, 1, 1),
fib (3, 1, 2),
fib (2, 2, 3),
fib (1, 3, 5),
fib (0, 5, 8) */
#tailrec
def fib (cnt: Int, low: Array[Int], high: Array[Int]): Array[Int] = {
if (cnt == 0) low else fib (cnt - 1, high, add (low, high)) }
/** generate 2 Arrays, size dependent on n of about 0.7*n + 1, big enough to
hold values and result. Result has to be printed in reverse order, from the highest bit
*/
def fibonacci (n: Int) = {
val lower = Array.fill (n * 7 / 10 + 1)(0) // [...000]
val higher = Array.fill (n * 7 / 10 + 1)(0) // [...000]
higher (0) = 1 // [...001]
val res = fib (n, lower, higher)
res.reverse.foreach (print)
println ()
res
}
fibonacci (n)
For fibonacci (10000) I get a result of nearly 7000 binary digits, and the relation 10/7 is constant, so the millionth Fibonacci digit will have about 1.4 M digits.
The better method would be to use Matrix Exponentiation, which would calculate n'th fib. in lg(n) time. ( usefull for various online coding contests) See Method 4 of This post.

Code Golf: New Year's Fireworks [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Closed 11 years ago.
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
The year 2009 is coming to an end, and with the economy and all, we'll save our money and instead of buying expensive fireworks, we'll celebrate in ASCII art this year.
The challenge
Given a set of fireworks and a time, take a picture of the firework at that very time and draw it to the console.
The best solution entered before midnight on New Year's Eve (UTC) will receive a bounty of 500 rep. This is code golf, so the number of characters counts heavily; however so do community votes, and I reserve the ultimate decision as to what is best/coolest/most creative/etc.
Input Data
Note that our coordinate system is left-to-right, bottom-to-top, so all fireworks are launched at a y-coordinate of 0 (zero).
The input data consists of fireworks of the form
(x, speed_x, speed_y, launch_time, detonation_time)
where
x is the position (column) where the firework is launched,
speed_x and speed_y are the horizontal and vertical velocity of the firework at launch time,
launch_time is the point in time that this firework is launched,
detonation_time is the point in time that this firework will detonate.
The firework data may be hardcoded in your program as a list of 5-tuples (or the equivalent in your language), not counting towards your character count. It must, however, be easy to change this data.
You may make the following assumptions:
there is a reasonable amount of fireworks (say, fewer then a hundred)
for each firework, all five numbers are integers within a reasonable range (say, 16 bits would suffice for each),
-20 <= x <= 820
-20 <= speed_x <= 20
0 < speed_y <= 20
launch_time >= 0
launch_time < detonation_time < launch_time + 50
The single additional piece of input data is the point of time which is supposed to be rendered. This is a non-negative integer that is given to you via standard input or command line argument (whichever you choose).
The idea is that (assuming your program is a python script called firework.py) this bash script gives you a nice firework animation:
#!/bin/bash
I=0
while (( 1 )) ; do
python firework.py $I
I=$(( $I + 1 ))
done
(feel free to put the equivalent .BAT file here).
Life of a firework
The life of a firework is as follows:
Before the launch time, it can be ignored.
At launch time, the rocket has the position (x, 0) and the speed vector (speed_x, speed_y).
For each time step, the speed vector is added to the position. With a little stretch applied to Newton's laws, we assume that the speed stays constant.
At detonation time, the rocket explodes into nine sparks. All nine sparks have the same position at this point in time (which is the position that the rocket would have, hadn't it exploded),
but their speeds differ. Each speed is based on the rocket's speed, with -20, 0, or 20 added to speed_x and -10, 0, or 10 added to speed_y. That's nine possible combinations.
After detonation time, gravity starts to pull: With each time step, the gravitational constant, which happens to be 2 (two), is subtracted from every spark's speed_y.
The horizontal speed_x stays constant.
For each time step after the detonation time, you first add the speed vector to the position, then subtract 2 from speed_y.
When a spark's y position drops below zero, you may forget about it.
Output
What we want is a picture of the firework the way it looks at the given point in time. We only look at the frame 0 <= x <= 789 and 0 <= y <= 239, mapping it to a 79x24 character output.
So if a rocket or spark has the position (247, 130), we draw a character in column 24 (zero-based, so it's the 25th column), row 13 (zero-based and counting from the bottom, so it's line 23 - 13 = 10, the 11th line
of the output).
Which character gets drawn depends on the current speed of the rocket / spark:
If the movement is horizontal*, i.e. speed_y == 0 or abs(speed_x) / abs(speed_y) > 2, the character is "-".
If the movement is vertical*, i.e. speed_x == 0 or abs(speed_y) / abs(speed_x) > 2, the character is "|".
Otherwise the movement is diagonal, and the character is "\" or "/" (you'll guess the right one).
If the same position gets drawn to more than once (even if it's the same character), we put "X" instead. So assuming you have a spark at (536, 119) and one at (531, 115), you draw an "X", regardless of their speeds.
* update: these are integer divisions, so the slope has to be at least 3, or at most 1/3, respectively
The output (written to standard output) is 24 lines, each terminated by a newline character. Trailing spaces are ignored, so you may, but don't need to, pad to a width of 79. The lines may not be longer than 79 characters (excluding the newline). All interior spacing must be space characters (ASCII 32).
Sample Data
Fireworks:
fireworks = [(628, 6, 6, 3, 33),
(586, 7, 11, 11, 23),
(185, -1, 17, 24, 28),
(189, 14, 10, 50, 83),
(180, 7, 5, 70, 77),
(538, -7, 7, 70, 105),
(510, -11, 19, 71, 106),
(220, -9, 7, 77, 100),
(136, 4, 14, 80, 91),
(337, -13, 20, 106, 128)]
Output at time 33:
\ | /
/ \
- | /
- | -
/ \
Output at time 77:
\
\
X
\
Output at time 93:
\ | /
\ / /
- - - \
\
/ \ \
Update: I have uploaded the expected output at the times 0 thru 99 to firework.ü-wie-geek.de/NUMBER.html, where NUMBER is the time. It includes debug information; click on a particle to see its current position, speed, etc. And yes, it's an umlaut domain. If your browser can't handle that (as obviously neither can Stack Overflow), try firework.xn---wie-geek-p9a.de.
Another update: As hinted at in the comments below, a longer firework is now available on YouTube. It was created with a modified version of MizardX' entry, with a total fireworks count of 170 (yes, that's more than the spec asked for, but the program handled it gracefully). Except for the color, the music, and the end screen, the animation can be recreated by any entry to this code golf. So, if you're geeky enough to enjoy an ASCII art firework (you know you are): Have fun, and a happy new year to all!
Heres my solution in Python:
c = [(628, 6, 6, 3, 33),
(586, 7, 11, 11, 23),
(185, -1, 17, 24, 28),
(189, 14, 10, 50, 83),
(180, 7, 5, 70, 77),
(538, -7, 7, 70, 105),
(510, -11, 19, 71, 106),
(220, -9, 7, 77, 100),
(136, 4, 14, 80, 91),
(337, -13, 20, 106, 128)]
t=input()
z=' '
s=([z]*79+['\n'])*23+[z]*79
def p(x,y,i,j):
if 0<=x<790 and 0<=y<240:p=x/10+(23-y/10)*80;I=abs(i);J=abs(j);s[p]='X-|\\/'[[s[p]!=z,I>=3*J,J>=3*I,i*j<0,1].index(1)]
for x,i,j,l,d in c:
T=t-l;x+=i*T
if t>=d:e=t-d;[p(x+X*e,j*T+e*(Y-e+1),i+X,j+Y-2*e)for X in -20,0,20 for Y in -10,0,10]
elif t>=l:p(x,j*T,i,j)
print ''.join(s)
Takes the time from the stdin and it has the nice number of 342 characters. I'm still trying to imagine how the OP got 320 :P
Edit:
This is the best I could get, 322 chars acording to wc
t=input()
s=([' ']*79+['\n'])*24
def p(x,y,i,j):
if 790>x>-1<y<240:p=x/10+(23-y/10)*80;I=abs(i);J=abs(j);s[p]='X-|\\/'[[s[p]>' ',I>=3*J,J>=3*I,i*j<0,1].index(1)]
for x,i,j,l,d in c:
T=t-l;x+=i*T;e=t-d
if t>=d:[p(x+X*e,j*T+e*(Y-e+1),i+X,j+Y-2*e)for X in-20,0,20for Y in-10,0,10]
elif t>=l:p(x,j*T,i,j)
print''.join(s),
Now that the winner is chosen – congratulations to Juan – here is my own solution, 304 characters in Python:
t=input()
Q=range
for y in Q(24):print"".join((["\\/|-"[3*(h*h>=9*v*v)or(v*v>=9*h*h)*2or h*v>0]for X,H,V,L,D in F for s,Z,K,P,u in[(t-D,t>D,t-L,G%3*20-20,G/3*10-10)for G in[Q(9),[4]][t<D]]for h,v in[[P+H,u+V-2*s*Z]]if((X+H*K+P*s)/10,23-(V*K-s*(Z*s-Z-u))/10)==(x,y)][:2]+[" ","X"])[::3][-1]for x in Q(79))
This is not really fast, because for each point in the 79x24 display, it loops through all fireworks to see if any of them is visible at this point.
Here is a version that tries to explain what's going on:
t=input()
Q=range
for y in Q(24):
line = ""
for x in Q(79):
chars = [] # will hold all characters that should be drawn at (x, y)
for X,H,V,L,D in F: # loop through the fireworks
s = t - D
Z = t > D
K = t - L
# if t < D, i.e. the rocket hasn't exploded yet, this is just [(0, 0)];
# otherwise it's all combinations of (-20, 0, 20) for x and (-10, 0, 10)
speed_deltas = [(G % 3 * 20 - 20, G / 3 * 10 -10) for G in [Q(9), [4]][t < D]]
for P, u in speed_deltas:
if x == (X + H*K + P*s)/10 and y == 23 - (V*K - s*(Z*s - Z - u))/10:
# the current horizontal and vertical speed of the particle
h = P + H
v = u + V - 2*s*Z
# this is identical to (but shorter than) abs(h) >= 3 * abs(v)
is_horizontal = h*h >= 9*v*v
is_vertical = v*v >= 9*h*h
is_northeast_southwest = h*v > 0
# a shorter way of saying
# char_index = (3 if is_horizontal else 2 if is_vertical else 1
# if is_northeast_southwest else 0)
char_index = 3 * is_horizontal or 2 * is_vertical or is_northeast_southwest
chars.append("\\/|-"[char_index])
# chars now contains all characters to be drawn to this point. So we have
# three possibilities: If chars is empty, we draw a space. If chars has
# one element, that's what we draw. And if chars has more than one element,
# we draw an "X".
actual_char = (chars[:2] + [" ", "X"])[::3][-1] # Yes, this does the trick.
line += actual_char
print line
Python:
fireworks = [(628, 6, 6, 3, 33),
(586, 7, 11, 11, 23),
(185, -1, 17, 24, 28),
(189, 14, 10, 50, 83),
(180, 7, 5, 70, 77),
(538, -7, 7, 70, 105),
(510, -11, 19, 71, 106),
(220, -9, 7, 77, 100),
(136, 4, 14, 80, 91),
(337, -13, 20, 106, 128)]
import sys
t = int(sys.argv[1])
particles = []
for x, speed_x, speed_y, launch_time, detonation_time in fireworks:
if t < launch_time:
pass
elif t < detonation_time:
x += speed_x * (t - launch_time)
y = speed_y * (t - launch_time)
particles.append((x, y, speed_x, speed_y))
else:
travel_time = t - detonation_time
x += (t - launch_time) * speed_x
y = (t - launch_time) * speed_y - travel_time * (travel_time - 1)
for dx in (-20, 0, 20):
for dy in (-10, 0, 10):
x1 = x + dx * travel_time
y1 = y + dy * travel_time
speed_x_1 = speed_x + dx
speed_y_1 = speed_y + dy - 2 * travel_time
particles.append((x1, y1, speed_x_1, speed_y_1))
rows = [[' '] * 79 for y in xrange(24)]
for x, y, speed_x, speed_y in particles:
x, y = x // 10, y // 10
if 0 <= x < 79 and 0 <= y < 24:
row = rows[23 - y]
if row[x] != ' ': row[x] = 'X'
elif speed_y == 0 or abs(speed_x) // abs(speed_y) > 2: row[x] = '-'
elif speed_x == 0 or abs(speed_y) // abs(speed_x) > 2: row[x] = '|'
elif speed_x * speed_y < 0: row[x] = '\\'
else: row[x] = '/'
print '\n'.join(''.join(row) for row in rows)
If you remove the initial fireworks declaration, compress variable-names to single characters, and whitespace to a minimum, you can get 590 characters.
C:
With all unnecessary whitespace removed (632 bytes excluding the fireworks declaration):
#define N 10
int F[][5]={628,6,6,3,33,586,7,11,11,23,185,-1,17,24,28,189,14,10,50,83,180,7,5,70,77,538,-7,7,70,105,510,-11,19,71,106,220,-9,7,77,100,136,4,14,80,91,337,-13,20,106,128};
#define G F[i]
#define R P[p]
g(x,y){if(y==0||abs(x)/abs(y)>2)return 45;if(x==0||abs(y)/abs(x)>2)return'|';if(x*y<0)return 92;return 47;}main(int A,char**B){int a,b,c,C[24][79]={},d,i,j,p=0,P[N*9][3],Q,t=atoi(B[1]),x,y;for(i=0;i<N;i++){if(t>=G[3]){a=t-G[3];x=G[0]+G[1]*a;y=G[2]*a;if(t<G[4]){R[0]=x;R[1]=y;R[2]=g(G[1],G[2]);p++;}else{b=t-G[4];y-=b*(b-1);for(c=-20;c<=20;c+=20){for(d=-10;d<=10;d+=10){R[0]=x+c*b;R[1]=y+d*b;R[2]=g(G[1]+c,G[2]+d-2*b);p++;}}}}}Q=p;for(p=0;p<Q;p++){x=R[0]/10;y=R[1]/10;if(R[0]>=0&&x<79&&R[1]>=0&&y<24)C[y][x]=C[y][x]?88:R[2];}for(i=23;i>=0;i--){for(j=0;j<79;j++)putchar(C[i][j]?C[i][j]:32);putchar(10);}}
And here's the exact same code with whitespace added for readability:
#define N 10
int F[][5] = {
628, 6, 6, 3, 33,
586, 7, 11, 11, 23,
185, -1, 17, 24, 28,
189, 14, 10, 50, 83,
180, 7, 5, 70, 77,
538, -7, 7, 70, 105,
510, -11, 19, 71, 106,
220, -9, 7, 77, 100,
136, 4, 14, 80, 91,
337, -13, 20, 106, 128
};
#define G F[i]
#define R P[p]
g(x, y) {
if(y == 0 || abs(x)/abs(y) > 2)
return 45;
if(x == 0 || abs(y)/abs(x) > 2)
return '|';
if(x*y < 0)
return 92;
return 47;
}
main(int A, char**B){
int a, b, c, C[24][79] = {}, d, i, j, p = 0, P[N*9][3], Q, t = atoi(B[1]), x, y;
for(i = 0; i < N; i++) {
if(t >= G[3]) {
a = t - G[3];
x = G[0] + G[1]*a;
y = G[2]*a;
if(t < G[4]) {
R[0] = x;
R[1] = y;
R[2] = g(G[1], G[2]);
p++;
} else {
b = t - G[4];
y -= b*(b-1);
for(c = -20; c <= 20; c += 20) {
for(d =- 10; d <= 10; d += 10) {
R[0] = x + c*b;
R[1] = y + d*b;
R[2] = g(G[1] + c, G[2] + d - 2*b);
p++;
}
}
}
}
}
Q = p;
for(p = 0; p < Q; p++) {
x = R[0]/10;
y = R[1]/10;
if(R[0] >= 0 && x < 79 && R[1] >= 0 && y < 24)
C[y][x] = C[y][x] ? 88 : R[2];
}
for(i = 23; i >= 0; i--) {
for(j = 0; j < 79; j++)
putchar(C[i][j] ? C[i][j] : 32);
putchar(10);
}
}
For Python, #MizardX's solution is nice, but clearly not codegolf-optimized -- besides the "don't really count" 333 characters of the prefix, namely:
fireworks = [(628, 6, 6, 3, 33),
(586, 7, 11, 11, 23),
(185, -1, 17, 24, 28),
(189, 14, 10, 50, 83),
(180, 7, 5, 70, 77),
(538, -7, 7, 70, 105),
(510, -11, 19, 71, 106),
(220, -9, 7, 77, 100),
(136, 4, 14, 80, 91),
(337, -13, 20, 106, 128)]
f = fireworks
### int sys argv append abs join f xrange
(the last comment is a helper for a little codegolf-aux script of mine that makes all feasible names 1-char mechanically -- it needs to be told what names NOT to minify;-), the shortest I can make that solution by squeezing whitespace is 592 characters (close enough to the 590 #MizardX claims).
Pulling out all the stops ("refactoring" the code in a codegolf mood), I get, after the prefix (I've used lowercase for single-character names I'm manually introducing or substituting, uppercase for those my codegolf-aux script substituted automatically):
import sys
Z=int(sys.argv[1])
Y=[]
e=Y.extend
for X,W,V,U,T in f:
if Z>=U:
z=Z-U;X+=W*z
if Z<T:e(((X,V*z,W,V),))
else:R=Z-T;e((X+Q*R,z*V-R*(R-1)+P*R,W+Q,V+P-2*R)for Q in(-20,0,20)for P in(-10,0,10))
K=[79*[' ']for S in range(24)]
for X,S,W,V in Y:
X,S=X/10,S/10
if(0<=X<79)&(0<=S<24):
J=K[23-S];v=abs(V);w=abs(W)
J[X]='X'if J[X]!=' 'else'-'if V==0 or w/v>2 else'|'if W==0 or v/w>2 else '\\'if W*V<0 else'/'
print '\n'.join(''.join(J)for J in K)
which measures in at 460 characters -- that's a reduction of 130, i.e. 130/590 = 22%.
Beyond 1-character names and obvious ways to minimize spacing, the key ideas include: single / for division (same as the nicer // for ints in Python 2.*), an if/else expression in lieu of an if/elif/else statement, extend with a genexp rather than a nested loop with append (allows the removal of some spaces and punctuation), not binding to a name subexpressions that occur just once, binding to a name subexpressions that would otherwise get repeated (including the .extend attribute lookup), semicolons rather than newlines where feasible (only if the separate lines would have to be indented, otherwise, counting a newline as 1 character, there is no saving).
Yep, readability suffers a bit, but that's hardly surprising in code golf;-).
Edit: after a lot more tightening, I now have a smaller program (same prefix):
Z=input()
K=[79*[' ']for S in range(24)];a=-10,0,10
def g(X,S,W,V):
X/=10;S/=10
if(0<=X<79)&(0<=S<24):J=K[23-S];v=abs(V);w=abs(W);J[X]=[[['/\\'[W*V<0],'|'][v>2.9*w],'-'][w>2.9*v],'X'][J[X]!=' ']
for X,W,V,U,T in f:
if Z>=U:
z=Z-U;X+=W*z
if Z<T:g(X,V*z,W,V)
else:R=Z-T;[g(X+Q*2*R,z*V-R*(R-1)+P*R,W+Q*2,V+P-2*R)for Q in a for P in a]
print'\n'.join(''.join(J)for J in K)
Still the same output, but now 360 characters -- exactly 100 fewer than my previous solution, which i've left as the first part of this answer (still well above the 320 the OP says he has, though!-).
I've taken advantage of the degree of freedom allowing the input-time value to come from stdin (input is much tighter than importing sys and using sys.argv[1]!-), eliminated the intermediate list (w/the extend calls and a final loop of it) in favor of the new function g which gets called directly and updates K as we go, found and removed some commonality, refactored the nested if/else expression into a complicated (but more concise;-) building and indexing of nested lists, used the fact that v>2.9*w is more concise than w==0 or v/w>2 (and always gives the same result in the range of values that are to be considered).
Edit: making K (the "screen image") into a 1-D list saves a further 26 characters, shrinking the following solution to 334 (still 14 above the OP's, but closing up...!-):
Z=input()
K=list(24*(' '*79+'\n'))
a=-10,0,10
def g(X,S,W,V):
if(0<=X<790)&(0<=S<240):j=80*(23-S/10)+X/10;v=abs(V);w=abs(W);K[j]=[[['/\\'[W*V<0],'|'][v>2.9*w],'-'][w>2.9*v],'X'][K[j]!=' ']
for X,W,V,U,T in f:
if Z>=U:
z=Z-U;X+=W*z
if Z<T:g(X,V*z,W,V)
else:R=Z-T;[g(X+Q*2*R,z*V-R*(R-1)+P*R,W+Q*2,V+P-2*R)for Q in a for P in a]
print ''.join(K),
Done in F# in 957* characters, and it's ugly as sin:
Array of fireworks:
let F = [(628,6,6,3,33);(586,7,11,11,23);(185,-1,17,24,28);(189,14,10,50,83);(180,7,5,70,77);(538,-7,7,70,105);(510,-11,19,71,106);(220,-9,7,77,100);(136,4,14,80,91);(337,-13,20,106,128)]
Remaining code
let M=List.map
let C=List.concat
let P=List.partition
let L t f r=(let s=P(fun(_,_,_,u,_)->not(t=u))f
(fst s, r#(M(fun(x,v,w,_,t)->x,0,v,w,t)(snd s))))
let X d e (x,y,v,w)=C(M(fun(x,y,v,w)->[x,y,v-d,w;x,y,v,w;x,y,v+d,w])[x,y,v,w-e;x,y,v,w;x,y,v,w+e])
let D t r s=(let P=P(fun(_,_,_,_,u)->not(t=u))r
(fst P,s#C(M(fun(x,y,v,w,_)->(X 20 10(x,y,v,w)))(snd P))))
let rec E t l f r s=(
let(a,m)=L t f (M(fun(x,y,v,w,t)->x+v,y+w,v,w,t)r)
let(b,c)=D t m (M(fun(x,y,v,w)->x+v,y+w,v,w-2)s)
if(t=l)then(a,b,c)else E(t+1)l a b c)
let N=printf
let G t=(
let(f,r,s)=E 0 t F [] []
let os=s#(M(fun(x,y,v,w,_)->(x,y,v,w))r)
for y=23 downto 0 do (
for x=0 to 79 do (
let o=List.filter(fun(v,w,_,_)->((v/10)=x)&&((w/10)=y))os
let l=o.Length
if l=0 then N" "
elif l=1 then
let(_,_,x,y)=o.Head
N(
if y=0||abs(x)/abs(y)>2 then"-"
elif x=0||abs(y)/abs(x)>2 then"|"
elif y*x>0 then"/"
else"\\")
elif o.Length>1 then N"X")
N"\n"))
[<EntryPointAttribute>]
let Z a=
G (int(a.[0]))
0
"Pretty" code:
let fxs = [(628,6,6,3,33);(586,7,11,11,23);(185,-1,17,24,28);(189,14,10,50,83);(180,7,5,70,77);(538,-7,7,70,105);(510,-11,19,71,106);(220,-9,7,77,100);(136,4,14,80,91);(337,-13,20,106,128)]
let movs xs =
List.map (fun (x, y, vx, vy) -> (x + vx, y + vy, vx, vy-2)) xs
let movr xs =
List.map (fun (x, y, vx, vy, dt) -> (x + vx, y + vy, vx, vy, dt)) xs
let launch t fs rs =
let split = List.partition(fun (lx, sx, sy, lt, dt) -> not (t = lt)) fs
(fst split, rs # (List.map(fun (lx, sx, sy, lt, dt) -> (lx, 0, sx, sy, dt)) (snd split)))
let split dx dy (x,y,sx,sy) =
List.concat (List.map (fun (x,y,sx,sy)->[(x,y,sx-dx,sy);(x,y,sx,sy);(x,y,sx+dx,sy)]) [(x,y,sx,sy-dy);(x,y,sx,sy);(x,y,sx,sy+dy)])
let detonate t rs ss =
let tmp = List.partition (fun (x, y, sx, sy, dt) -> not (t = dt)) rs
(fst tmp, ss # List.concat (List.map(fun (x, y, sx, sy, dt) -> (split 20 10 (x, y, sx, sy))) (snd tmp)))
let rec simulate t l fs rs ss =
let (nfs, trs) = launch t fs (movr rs)
let (nrs, nss) = detonate t trs (movs ss)
if (t = l) then (nfs,nrs,nss)
else
simulate (t+1) l nfs nrs nss
let screen t =
let (fs, rs, ss) = simulate 0 t fxs [] []
let os = ss # (List.map(fun (x, y, sx, sy,_) -> (x, y, sx, sy)) rs)
for y = 23 downto 0 do
for x = 0 to 79 do
let o = List.filter(fun (px,py,_,_)->((px/10)=x) && ((py/10)=y)) os
if o.Length = 0 then printf " "
elif o.Length = 1 then
let (_,_,sx,sy) = o.Head
printf (
if sy = 0 || abs(sx) / abs(sy) > 2 then "-"
elif sx = 0 || abs(sy) / abs(sx) > 2 then "|"
elif sy * sx > 0 then "/"
else"\\"
)
elif o.Length > 1 then printf "X"
printfn ""
[<EntryPointAttribute>]
let main args =
screen (int(args.[0]))
0
Completely stolenrewritten with new and improved logic. This is as close as I could get to Python. You can see the weakness of F# not being geared toward ad hoc scripting here, where I have to explicitly convert V and W to a float, declare a main function with an ugly attribute to get the command line args, and I have to reference the .NET System.Console.Write to get a pretty output.
Oh well, good exercise to learn a language with.
Here's the new code, at 544 bytes:
let Q p t f=if p then t else f
let K=[|for i in 1..1920->Q(i%80>0)' ''\n'|]
let g(X,S,W,V)=
if(X>=0&&X<790&&S>=0&&S<240)then(
let (j,v,w)=(80*(23-S/10)+X/10,abs(float V),abs(float W))
Array.set K j (Q(K.[j]=' ')(Q(w>2.9*v)'-'(Q(v>2.9*w)'|'(Q(W*V>0)'/''\\')))'X'))
let a=[-10;0;10]
[<EntryPointAttribute>]
let m s=
let Z=int s.[0]
for (X,W,V,U,T) in F do(
if Z>=U then
let z,R=Z-U,Z-T
let x=X+W*z
if(Z<T)then(g(x,V*z,W,V))else(for e in[|for i in a do for j in a->(x+j*2*R,z*V-R*(R-1)+i*R,W+j*2,V+i-2*R)|]do g e))
System.Console.Write K
0
Haskell
import Data.List
f=[(628,6,6,3,33),(586,7,11,11,23),(185,-1,17,24,28),(189,14,10,50,83),(180,7,5,70,77),(538,-7,7,70,105),(510,-11,19,71,106),(220,-9,7,77,100),(136,4,14,80,91),(337,-13,20,106,128)]
c=filter
d=True
e=map
a(_,_,_,t,_)=t
b(_,_,_,_,t)=t
aa(_,y,_,_)=y
ab(x,t,y,_,u)=(x,0,t,y,u)
ac(x,y,t,u,_)=[(x,y,t+20,u+10),(x,y,t,u+10),(x,y,t-20,u+10),(x,y,t+20,u),(x,y,t,u),(x,y,t-20,u),(x,y,t+20,u-10),(x,y,t,u-10),(x,y,t-20,u-10)]
g(x,y,t,u,v)=(x+t,y+u,t,u,v)
h(x,y,t,u)=(x+t,y+u,t,u-2)
i=(1,f,[],[])
j s 0=s
j(t,u,v,w)i=j(t+1,c((/=t).a)u,c((> t).b)x++(e ab.c((==t).a))u,c((>0).aa)(e h w)++(concat.e ac.c((==t).b))x)(i-1)
where x=e g v
k x y
|x==0='|'
|3*abs y<=abs x='-'
|3*abs x<=abs y='|'
|(y<0&&x>0)||(y>0&&x<0)='\\'
|d='/'
l(x,y,t,u,_)=m(x,y,t,u)
m(x,y,t,u)=(div x 10,23-div y 10,k t u)
n(x,y,_)(u,v,_)
|z==EQ=compare x u
|d=z
where z=compare y v
o((x,y,t):(u,v,w):z)
|x==u&&y==v=o((x,y,'X'):z)
|d=(x,y,t):(o((u,v,w):z))
o x=x
q _ y []
|y==23=""
|d='\n':(q 0(y+1)[])
q v u((x,y,z):t)
|u>22=""
|v>78='\n':(q 0(u+1)((x,y,z):t))
|u/=y='\n':(q 0(u+1)((x,y,z):t))
|v/=x=' ':(q(v+1)u((x,y,z):t))
|d = z:(q(v+1)u t)
p(_,_,v,w)=q 0 0((c z.o.sortBy n)((e l v)++(e m w)))
where z(x,y,_)=x>=0&&x<79&&y>=0
r x=do{z <- getChar;(putStr.p)x}
s=e(r.j i)[1..]
main=foldr(>>)(return())s
Not nearly as impressive as MizardX's, coming in at 1068 characters if you remove the f=… declaration, but hell, it was fun. It's been a while since I've had a chance to play with Haskell.
The (slightly) prettier version is also available.
Edit: Ack. Rereading, I don't quite meet the spec.: this version prints a new screen of firework display every time you press a key, and requires ^C to quit; it doesn't take a command line argument and print out the relevant screen.
Perl
Assuming firework data is defined as:
#f = (
[628, 6, 6, 3, 33],
[586, 7, 11, 11, 23],
[185, -1, 17, 24, 28],
[189, 14, 10, 50, 83],
[180, 7, 5, 70, 77],
[538, -7, 7, 70, 105],
[510, -11, 19, 71, 106],
[220, -9, 7, 77, 100],
[136, 4, 14, 80, 91],
[337, -13, 20, 106, 128]
);
$t=shift;
for(#f){
($x,$c,$d,$l,$e)=#$_;
$u=$t-$l;
next if$u<0;
$x+=$c*$u;
$h=$t-$e;
push#p,$t<$e?[$x,$d*$u,$c,$d]:map{$f=$_;map{[$x+$f*$h,($u*$d-$h*($h-1))+$_*$h,$c+$f,$d+$_-2*$h]}(-10,0,10)}(-20,0,20)
}
push#r,[($")x79]for(1..24);
for(#p){
($x,$y,$c,$d)=#$_;
if (0 <= $x && ($x=int$x/10) < 79 && 0 <= $y && ($y=int$y/10) < 24) {
#$_[$x]=#$_[$x]ne$"?'X':!$d||abs int$c/$d>2?'-':!$c||abs int$d/$c>2?'|':$c*$d<0?'\\':'/'for$r[23 - $y]
}
}
$"='';
print$.,map{"#$_\n"}#r
Compressed, it comes in at 433 characters. (see edits for history)
This is based off of pieces of multiple previous answers (mostly MizardX's) and can definitely be improved upon. The guilt of procrastinating other, job-related tasks means i have to give up for now.
Forgive the edit -- pulling out all of the tricks I know, this can be compressed to 356 char:
sub p{
($X,$=,$C,$D)=#_;
if(0<=$X&($X/=10)<79&0<=$=&($=/=10)<24){
#$_[$X]=#$_[$X]ne$"?X:$D&&abs$C/$D<3?$C&&abs$D/$C<3?
$C*$D<0?'\\':'/':'|':'-'for$r[23-$=]
}
}
#r=map[($")x79],1..24;
$t=pop;
for(#f){
($x,$c,$d,$u,$e)=#$_;
$x-=$c*($u-=$t);
$u>0?1:($h=$t-$e)<0
?p$x,-$d*$u,$c,$d
:map{for$g(-10,0,10){p$x+$_*$h,$h*(1-$h+$g)-$u*$d,$c+$_,$d+$g-2*$h}}-20,0,20
}
print#$_,$/for#r
$= is a special Perl variable (along with $%, $-, and $?) that can only take on integer values. Using it eliminates the need to use the int function.
FORTRAN 77
From the prehistoric languages department, here's my entry – in FORTRAN 77.
2570 chars including the initialization, a handful of spaces and some unnecessary whitespace, but I don't think it's likely to win for brevity. Especially since e.g. 6 leading spaces in each line are mandatory.
I called this file fireworks.ftn and compiled it with gfortran on a Linux system.
implicit integer(a-z)
parameter (n=10)
integer fw(5,n) /
+ 628, 6, 6, 3, 33,
+ 586, 7, 11, 11, 23,
+ 185, -1, 17, 24, 28,
+ 189, 14, 10, 50, 83,
+ 180, 7, 5, 70, 77,
+ 538, -7, 7, 70, 105,
+ 510, -11, 19, 71, 106,
+ 220, -9, 7, 77, 100,
+ 136, 4, 14, 80, 91,
+ 337, -13, 20, 106, 128
+ /
integer p(6, 1000) / 6000 * -1 /
character*79 s(0:23)
character z
c Transform input
do 10 r=1,n
p(1, r) = 0
do 10 c=1,5
10 p(c+1, r) = fw(c, r)
c Input end time
read *, t9
c Iterate from 1 to end time
do 62 t=1,t9
do 61 q=1,1000
if (p(1,q) .lt. 0 .or. t .lt. p(5,q)) goto 61
if (p(6,q).gt.0.and.t.gt.p(5,q) .or. t.gt.abs(p(6,q))) then
p(1,q) = p(1,q) + p(4,q)
p(2,q) = p(2,q) + p(3,q)
endif
if (t .lt. abs(p(6,q))) goto 61
if (t .gt. abs(p(6,q))) then
p(4,q) = p(4,q) - 2
elseif (t .eq. p(6,q)) then
c Detonation: Build 9 sparks
do 52 m=-1,1
do 51 k=-1,1
c Find a free entry in p and fill it with a spark
do 40 f=1,1000
if (p(1,f) .lt. 0) then
do 20 j=1,6
20 p(j,f) = p(j,q)
p(3,f) = p(3,q) + 20 * m
p(4,f) = p(4,q) + 10 * k
p(6,f) = -p(6,q)
goto 51
endif
40 continue
51 continue
52 continue
c Delete the original firework
p(1,q) = -1
endif
61 continue
62 continue
c Prepare output
do 70 r=0,23
70 s(r) = ' '
do 80 q=1,1000
if (p(1,q) .lt. 0) goto 80
if (p(5,q) .gt. t9) goto 80
y = p(1,q) / 10
if (y .lt. 0 .or. y .gt. 23) goto 80
x = p(2,q) / 10
if (x .lt. 0 .or. x .gt. 79) goto 80
if (s(y)(x+1:x+1) .ne. ' ') then
z = 'X'
elseif ((p(4,q) .eq. 0) .or. abs(p(3,q) / p(4,q)) .gt. 2) then
z = '-'
elseif ((p(3,q) .eq. 0) .or. abs(p(4,q) / p(3,q)) .gt. 2) then
z = '|'
elseif (sign(1, p(3,q)) .eq. sign(1, p(4,q))) then
z = '/'
else
z = '\'
endif
s(y)(x+1:x+1) = z
80 continue
c Output
do 90 r=23,0,-1
90 print *, s(r)
end
Here's a smaller Haskell implementation. It's 911 characters; minus the fireworks definition, it's 732 characters:
import System
z=789
w=239
r=replicate
i=foldl
main=do{a<-getArgs;p(f[(628,6,6,3,33),(586,7,11,11,23),(185,-1,17,24,28),(189,14,10,50,83),(180,7,5,70,77),(538,-7,7,70,105),(510,-11,19,71,106),(220,-9,7,77,100),(136,4,14,80,91),(337,-13,20,106,128)](read(a!!0)::Int));}
p[]=return()
p(f:g)=do{putStrLn f;p g}
f s t=i(a t)(r 24(r 79' '))s
a t f(x,s,y,l,d)=if t<l then f else if t<d then c f((x+s*u,y*u),(s,y))else i c f(map(v(t-d)(o(d-l)(x,0)(s,y)))[(g s,h y)|g<-[id,(subtract 20),(+20)],h<-[id,(subtract 10),(+10)]])where u=t-l
v 0(x,y)(vx,vy)=((x,y),(vx,vy))
v t(x,y)(vx,vy)=v(t-1)(x+vx,y+vy)(vx,vy-2)
o t(x,y)(vx,vy)=(x+(vx*t),y+(vy*t))
c f((x,y),(vx,vy))=if x<0||x>=z||y<0||y>=w then f else(take m f)++[(take n r)++[if d/=' 'then 'x'else if vy==0||abs(vx`div`vy)>2 then '-'else if vx==0||abs(vy`div`vx)>2 then '|'else if vx*vy>=0 then '/'else '\\']++(drop(n+1)r)]++(drop(m+1)f)where{s=w-y;n=x`div`10;m=s`div`10;r=f!!m;d=r!!n}
Here's the non-compressed version for the curious:
import System
sizeX = 789
sizeY = 239
main = do
args <- getArgs
printFrame (frame fireworks (read (args !! 0) :: Int))
where
fireworks = [
(628, 6, 6, 3, 33),
(586, 7, 11, 11, 23),
(185, -1, 17, 24, 28),
(189, 14, 10, 50, 83),
(180, 7, 5, 70, 77),
(538, -7, 7, 70, 105),
(510, -11, 19, 71, 106),
(220, -9, 7, 77, 100),
(136, 4, 14, 80, 91),
(337, -13, 20, 106, 128)]
printFrame :: [String] -> IO ()
printFrame [] = return ()
printFrame (f:fs) = do
putStrLn f
printFrame fs
frame :: [(Int,Int,Int,Int,Int)] -> Int -> [String]
frame specs time =
foldl (applyFirework time)
(replicate 24 (replicate 79 ' ')) specs
applyFirework :: Int -> [String] -> (Int,Int,Int,Int,Int) -> [String]
applyFirework time frame (x,sx,sy,lt,dt) =
if time < lt then frame
else if time < dt then
drawChar frame
((x + sx * timeSinceLaunch, sy * timeSinceLaunch), (sx,sy))
else
foldl drawChar frame
(
map
(
posVelOverTime (time - dt)
(posOverTime (dt - lt) (x,0) (sx, sy))
)
[
(fx sx, fy sy) |
fx <- [id,(subtract 20),(+20)],
fy <- [id,(subtract 10),(+10)]
]
)
where timeSinceLaunch = time - lt
posVelOverTime :: Int -> (Int,Int) -> (Int,Int) -> ((Int,Int),(Int,Int))
posVelOverTime 0 (x,y) (vx,vy) = ((x,y),(vx,vy))
posVelOverTime time (x,y) (vx,vy) =
posVelOverTime (time - 1) (x+vx, y+vy) (vx, vy - 2)
posOverTime :: Int -> (Int,Int) -> (Int,Int) -> (Int,Int)
posOverTime time (x,y) (vx, vy) = (x + (vx * time), y + (vy * time))
drawChar :: [String] -> ((Int,Int),(Int,Int)) -> [String]
drawChar frame ((x,y),(vx,vy)) =
if x < 0 || x >= sizeX || y < 0 || y >= sizeY then frame
else
(take mappedY frame)
++
[
(take mappedX row)
++
[
if char /= ' ' then 'x'
else if vy == 0 || abs (vx `div` vy) > 2 then '-'
else if vx == 0 || abs (vy `div` vx) > 2 then '|'
else if vx * vy >= 0 then '/'
else '\\'
]
++ (drop (mappedX + 1) row)
]
++ (drop (mappedY + 1) frame)
where
reversedY = sizeY - y
mappedX = x `div` 10
mappedY = reversedY `div` 10
row = frame !! mappedY
char = row !! mappedX
First draft in Tcl8.5 913 bytes excluding fireworks definition:
set F {
628 6 6 3 33
586 7 11 11 23
185 -1 17 24 28
189 14 10 50 83
180 7 5 70 77
538 -7 7 70 105
510 -11 19 71 106
220 -9 7 77 100
136 4 14 80 91
337 -13 20 106 128
}
namespace import tcl::mathop::*
proc # {a args} {interp alias {} $a {} {*}$args}
# : proc
# = set
# D d p
# up upvar 1
# < append out
# _ foreach
# e info exists
# ? if
: P {s d t l} {+ $s [* $d [- $t $l]]}
: > x {= x}
: d {P x X y Y} {up $P p
= x [/ $x 10]
= y [/ $y 10]
= p($x,$y) [? [e p($x,$y)] {> X} elseif {
$Y==0||abs($X)/abs($Y)>2} {> -} elseif {
$X==0||abs($Y)/abs($X)>2} {> |} elseif {
$X*$Y<0} {> \\} {> /}]}
: r {P} {up $P p
= out ""
for {= y 23} {$y >= 0} {incr y -1} {
for {= x 0} {$x < 79} {incr x} {? {[e p($x,$y)]} {< $p($x,$y)} {< " "}}
< "\n"}
puts $out}
: s {F t} {array set p {}
_ {x X Y l d} $F {? {$t >= $l} {? {$t < $d} {= x [P $x $X $t $l]
= y [P 0 $Y $t $l]
D $x $X $y $Y} {= x [P $x $X $d $l]
= y [P 0 $Y $d $l]
= v [- $t $d]
_ dx {-20 0 20} {_ dy {-10 0 10} {= A [+ $X $dx]
= B [- [+ $Y $dy] [* 2 $v]]
= xx [P $x $A $v 0]
= yy [P $y $B $v 0]
D $xx $A $yy $B}}}}}
r p}
s $F [lindex $argv 0]
Optimized to the point of unreadability. Still looking for room to improve. Most of the compression basically uses command aliasing substituting single characters for command names. For example, function definitions are done using Forth-like : syntax.
Here's the uncompressed version:
namespace import tcl::mathop::*
set fireworks {
628 6 6 3 33
586 7 11 11 23
185 -1 17 24 28
189 14 10 50 83
180 7 5 70 77
538 -7 7 70 105
510 -11 19 71 106
220 -9 7 77 100
136 4 14 80 91
337 -13 20 106 128
}
proc position {start speed time launch} {
+ $start [* $speed [- $time $launch]]
}
proc give {x} {return $x}
proc draw {particles x speedX y speedY} {
upvar 1 $particles p
set x [/ $x 10]
set y [/ $y 10]
set p($x,$y) [if [info exists p($x,$y)] {
give X
} elseif {$speedY == 0 || abs(double($speedX))/abs($speedY) > 2} {
give -
} elseif {$speedX == 0 || abs(double($speedY))/abs($speedX) > 2} {
give |
} elseif {$speedX * $speedY < 0} {
give \\
} else {
give /
}
]
}
proc render {particles} {
upvar 1 $particles p
set out ""
for {set y 23} {$y >= 0} {incr y -1} {
for {set x 0} {$x < 79} {incr x} {
if {[info exists p($x,$y)]} {
append out $p($x,$y)
} else {
append out " "
}
}
append out "\n"
}
puts $out
}
proc show {fireworks time} {
array set particles {}
foreach {x speedX speedY launch detonate} $fireworks {
if {$time >= $launch} {
if {$time < $detonate} {
set x [position $x $speedX $time $launch]
set y [position 0 $speedY $time $launch]
draw particles $x $speedX $y $speedY
} else {
set x [position $x $speedX $detonate $launch]
set y [position 0 $speedY $detonate $launch]
set travel [- $time $detonate]
foreach dx {-20 0 20} {
foreach dy {-10 0 10} {
set speedXX [+ $speedX $dx]
set speedYY [- [+ $speedY $dy] [* 2 $travel]]
set xx [position $x $speedXX $travel 0]
set yy [position $y $speedYY $travel 0]
draw particles $xx $speedXX $yy $speedYY
}
}
}
}
}
render particles
}
show $fireworks [lindex $argv 0]
First Post hahaha
http://zipts.com/position.php?s=0
not my final submission but could not resist
Btw: Characters 937 not counting spaces (do we count spaces? )
My answer is at http://www.starenterprise.se/fireworks.html
all done in javascript.
and no I didn't bother to make it ashortap, I just wanted to see if I could.
Clojure
Unindented, without input output and unnecessary whitespace, it comes to 640 characters - exactly double the best value :( Thus, I'm not providing a "blank optimized" version in an attempt to win at brevity.
(def fw [
[628 6 6 3 33]
[586 7 11 11 23]
[185 -1 17 24 28]
[189 14 10 50 83]
[180 7 5 70 77]
[538 -7 7 70 105]
[510 -11 19 71 106]
[220 -9 7 77 100]
[136 4 14 80 91]
[337 -13 20 106 128]
])
(defn rr [x y u v dt g] (if (<= dt 0) [x y u v] (recur (+ x u) (+ y v) u (+ v g) (dec dt) g)))
(defn pp [t f]
(let [y 0 [x u v a d] f r1 (rr x y u v (- (min t d) a) 0)]
(if (< t a)
'()
(if (< t d)
(list r1)
(for [m '(-20 0 20) n '(-10 0 10)]
(let [[x y u v] r1]
(rr x y (+ u m) (+ v n) (- t d) -2)))))))
(defn at [x y t]
(filter #(and (= x (quot (first %) 10)) (= y (quot (second %) 10))) (apply concat (map #(pp t %) fw))))
(defn g [h]
(if (empty? h) \space
(if (next h) \X
(let [[x y u v] (first h)]
(cond
(or (zero? v) (> (* (/ u v) (/ u v)) 4)) \-
(or (zero? u) (> (* (/ v u) (/ v u)) 4)) \|
(= (neg? u) (neg? v)) \/
:else \\
)))))
(defn q [t]
(doseq [r (range 23 -1 -1)]
(doseq [c (range 0 80)]
(print (g (at c r t))))
(println)))
(q 93)

Getting a specific digit from a ratio expansion in any base (nth digit of x/y)

Is there an algorithm that can calculate the digits of a repeating-decimal ratio without starting at the beginning?
I'm looking for a solution that doesn't use arbitrarily sized integers, since this should work for cases where the decimal expansion may be arbitrarily long.
For example, 33/59 expands to a repeating decimal with 58 digits. If I wanted to verify that, how could I calculate the digits starting at the 58th place?
Edited - with the ratio 2124679 / 2147483647, how to get the hundred digits in the 2147484600th through 2147484700th places.
OK, 3rd try's a charm :)
I can't believe I forgot about modular exponentiation.
So to steal/summarize from my 2nd answer, the nth digit of x/y is the 1st digit of (10n-1x mod y)/y = floor(10 * (10n-1x mod y) / y) mod 10.
The part that takes all the time is the 10n-1 mod y, but we can do that with fast (O(log n)) modular exponentiation. With this in place, it's not worth trying to do the cycle-finding algorithm.
However, you do need the ability to do (a * b mod y) where a and b are numbers that may be as large as y. (if y requires 32 bits, then you need to do 32x32 multiply and then 64-bit % 32-bit modulus, or you need an algorithm that circumvents this limitation. See my listing that follows, since I ran into this limitation with Javascript.)
So here's a new version.
function abmody(a,b,y)
{
var x = 0;
// binary fun here
while (a > 0)
{
if (a & 1)
x = (x + b) % y;
b = (2 * b) % y;
a >>>= 1;
}
return x;
}
function digits2(x,y,n1,n2)
{
// the nth digit of x/y = floor(10 * (10^(n-1)*x mod y) / y) mod 10.
var m = n1-1;
var A = 1, B = 10;
while (m > 0)
{
// loop invariant: 10^(n1-1) = A*(B^m) mod y
if (m & 1)
{
// A = (A * B) % y but javascript doesn't have enough sig. digits
A = abmody(A,B,y);
}
// B = (B * B) % y but javascript doesn't have enough sig. digits
B = abmody(B,B,y);
m >>>= 1;
}
x = x % y;
// A = (A * x) % y;
A = abmody(A,x,y);
var answer = "";
for (var i = n1; i <= n2; ++i)
{
var digit = Math.floor(10*A/y)%10;
answer += digit;
A = (A * 10) % y;
}
return answer;
}
(You'll note that the structures of abmody() and the modular exponentiation are the same; both are based on Russian peasant multiplication.)
And results:
js>digits2(2124679,214748367,214748300,214748400)
20513882650385881630475914166090026658968726872786883636698387559799232373208220950057329190307649696
js>digits2(122222,990000,100,110)
65656565656
js>digits2(1,7,1,7)
1428571
js>digits2(1,7,601,607)
1428571
js>digits2(2124679,2147483647,2147484600,2147484700)
04837181235122113132440537741612893408915444001981729642479554583541841517920532039329657349423345806
edit: (I'm leaving post here for posterity. But please don't upvote it anymore: it may be theoretically useful but it's not really practical. I have posted another answer which is much more useful from a practical point of view, doesn't require any factoring, and doesn't require the use of bignums.)
#Daniel Bruckner has the right approach, I think. (with a few additional twists required)
Maybe there's a simpler method, but the following will always work:
Let's use the examples q = x/y = 33/57820 and 44/65 in addition to 33/59, for reasons that may become clear shortly.
Step 1: Factor the denominator (specifically factor out 2's and 5's)
Write q = x/y = x/(2a25a5z). Factors of 2 and 5 in the denominator do not cause repeated decimals. So the remaining factor z is coprime to 10. In fact, the next step requires factoring z, so you might as well factor the whole thing.
Calculate a10 = max(a2, a5) which is the smallest exponent of 10 that is a multiple of the factors of 2 and 5 in y.
In our example 57820 = 2 * 2 * 5 * 7 * 7 * 59, so a2 = 2, a5 = 1, a10 = 2, z = 7 * 7 * 59 = 2891.
In our example 33/59, 59 is a prime and contains no factors of 2 or 5, so a2 = a5 = a10 = 0.
In our example 44/65, 65 = 5*13, and a2 = 0, a5 = a10 = 1.
Just for reference I found a good online factoring calculator here. (even does totients which is important for the next step)
Step 2: Use Euler's Theorem or Carmichael's Theorem.
What we want is a number n such that 10n - 1 is divisible by z, or in other words, 10n ≡ 1 mod z. Euler's function φ(z) and Carmichael's function λ(z) will both give you valid values for n, with λ(z) giving you the smaller number and φ(z) being perhaps a little easier to calculate. This isn't too hard, it just means factoring z and doing a little math.
φ(2891) = 7 * 6 * 58 = 2436
λ(2891) = lcm(7*6, 58) = 1218
This means that 102436 ≡ 101218 ≡ 1 (mod 2891).
For the simpler fraction 33/59, φ(59) = λ(59) = 58, so 1058 ≡ 1 (mod 59).
For 44/65 = 44/(5*13), φ(13) = λ(13) = 12.
So what? Well, the period of the repeating decimal must divide both φ(z) and λ(z), so they effectively give you upper bounds on the period of the repeating decimal.
Step 3: More number crunching
Let's use n = λ(z). If we subtract Q' = 10a10x/y from Q'' = 10(a10 + n)x/y, we get:
m = 10a10(10n - 1)x/y
which is an integer because 10a10 is a multiple of the factors of 2 and 5 of y, and 10n-1 is a multiple of the remaining factors of y.
What we've done here is to shift left the original number q by a10 places to get Q', and shift left q by a10 + n places to get Q'', which are repeating decimals, but the difference between them is an integer we can calculate.
Then we can rewrite x/y as m / 10a10 / (10n - 1).
Consider the example q = 44/65 = 44/(5*13)
a10 = 1, and λ(13) = 12, so Q' = 101q and Q'' = 1012+1q.
m = Q'' - Q' = (1012 - 1) * 101 * (44/65) = 153846153846*44 = 6769230769224
so q = 6769230769224 / 10 / (1012 - 1).
The other fractions 33/57820 and 33/59 lead to larger fractions.
Step 4: Find the nonrepeating and repeating decimal parts.
Notice that for k between 1 and 9, k/9 = 0.kkkkkkkkkkkkk...
Similarly note that a 2-digit number kl between 1 and 99, k/99 = 0.klklklklklkl...
This generalizes: for k-digit patterns abc...ij, this number abc...ij/(10k-1) = 0.abc...ijabc...ijabc...ij...
If you follow the pattern, you'll see that what we have to do is to take this (potentially) huge integer m we got in the previous step, and write it as m = s*(10n-1) + r, where 1 ≤ r < 10n-1.
This leads to the final answer:
s is the non-repeating part
r is the repeating part (zero-padded on the left if necessary to ensure that it is n digits)
with a10 =
0, the decimal point is between the
nonrepeating and repeating part; if
a10 > 0 then it is located
a10 places to the left of
the junction between s and r.
For 44/65, we get 6769230769224 = 6 * (1012-1) + 769230769230
s = 6, r = 769230769230, and 44/65 = 0.6769230769230 where the underline here designates the repeated part.
You can make the numbers smaller by finding the smallest value of n in step 2, by starting with the Carmichael function λ(z) and seeing if any of its factors lead to values of n such that 10n ≡ 1 (mod z).
update: For the curious, the Python interpeter seems to be the easiest way to calculate with bignums. (pow(x,y) calculates xy, and // and % are integer division and remainder, respectively.) Here's an example:
>>> N = pow(10,12)-1
>>> m = N*pow(10,1)*44//65
>>> m
6769230769224
>>> r=m%N
>>> r
769230769230
>>> s=m//N
>>> s
6
>>> 44/65
0.67692307692307696
>>> N = pow(10,58)-1
>>> m=N*33//59
>>> m
5593220338983050847457627118644067796610169491525423728813
>>> r=m%N
>>> r
5593220338983050847457627118644067796610169491525423728813
>>> s=m//N
>>> s
0
>>> 33/59
0.55932203389830504
>>> N = pow(10,1218)-1
>>> m = N*pow(10,2)*33//57820
>>> m
57073676928398478035281909373919059149083362158422691110342442061570390868211691
45624351435489450017295053614666205465236942234520927014873746108612936700103770
32168799723279142165340712556208924247665167762020062262193012798339674852992044
27533725354548599100657212037357315807679003804911795226565202352127291594603943
27222414389484607402282947077135939121411276374956762365963334486336907644413697
68246281563472846765824974057419578000691802144586648218609477689380837080594949
84434451746800415081286751988931165686613628502248356969906606710480802490487720
51193358699411968177101349014181943964026288481494292632307160152196471809062608
09408509166378415773088896575579384296091317883085437564856451054998270494638533
37945347630577654790729851262538913870632998962296783120027672085783465928744379
10757523348322379799377378069872016603251470079557246627464545140089934278796264
26841923209961950882047734347976478727084053960567277758561051539259771705292286
40608785887236250432376340366655136630923555863023175371843652715323417502594258
04219993081978554133517813905223106191629194050501556554825319958491871324801106
88343133863714977516430300933932895191975095122794880664130058803182289865098581
80560359737115185
>>> r=m%N
>>> r
57073676928398478035281909373919059149083362158422691110342442061570390868211691
45624351435489450017295053614666205465236942234520927014873746108612936700103770
32168799723279142165340712556208924247665167762020062262193012798339674852992044
27533725354548599100657212037357315807679003804911795226565202352127291594603943
27222414389484607402282947077135939121411276374956762365963334486336907644413697
68246281563472846765824974057419578000691802144586648218609477689380837080594949
84434451746800415081286751988931165686613628502248356969906606710480802490487720
51193358699411968177101349014181943964026288481494292632307160152196471809062608
09408509166378415773088896575579384296091317883085437564856451054998270494638533
37945347630577654790729851262538913870632998962296783120027672085783465928744379
10757523348322379799377378069872016603251470079557246627464545140089934278796264
26841923209961950882047734347976478727084053960567277758561051539259771705292286
40608785887236250432376340366655136630923555863023175371843652715323417502594258
04219993081978554133517813905223106191629194050501556554825319958491871324801106
88343133863714977516430300933932895191975095122794880664130058803182289865098581
80560359737115185
>>> s=m//N
>>> s
0
>>> 33/57820
0.00057073676928398479
with the overloaded Python % string operator usable for zero-padding, to see the full set of repeated digits:
>>> "%01218d" % r
'0570736769283984780352819093739190591490833621584226911103424420615703908682116
91456243514354894500172950536146662054652369422345209270148737461086129367001037
70321687997232791421653407125562089242476651677620200622621930127983396748529920
44275337253545485991006572120373573158076790038049117952265652023521272915946039
43272224143894846074022829470771359391214112763749567623659633344863369076444136
97682462815634728467658249740574195780006918021445866482186094776893808370805949
49844344517468004150812867519889311656866136285022483569699066067104808024904877
20511933586994119681771013490141819439640262884814942926323071601521964718090626
08094085091663784157730888965755793842960913178830854375648564510549982704946385
33379453476305776547907298512625389138706329989622967831200276720857834659287443
79107575233483223797993773780698720166032514700795572466274645451400899342787962
64268419232099619508820477343479764787270840539605672777585610515392597717052922
86406087858872362504323763403666551366309235558630231753718436527153234175025942
58042199930819785541335178139052231061916291940505015565548253199584918713248011
06883431338637149775164303009339328951919750951227948806641300588031822898650985
8180560359737115185'
As a general technique, rational fractions have a non-repeating part followed by a repeating part, like this:
nnn.xxxxxxxxrrrrrr
xxxxxxxx is the nonrepeating part and rrrrrr is the repeating part.
Determine the length of the nonrepeating part.
If the digit in question is in the nonrepeating part, then calculate it directly using division.
If the digit in question is in the repeating part, calculate its position within the repeating sequence (you now know the lengths of everything), and pick out the correct digit.
The above is a rough outline and would need more precision to implement in an actual algorithm, but it should get you started.
AHA! caffiend: your comment to my other (longer) answer (specifically "duplicate remainders") leads me to a very simple solution that is O(n) where n = the sum of the lengths of the nonrepeating + repeating parts, and requires only integer math with numbers between 0 and 10*y where y is the denominator.
Here's a Javascript function to get the nth digit to the right of the decimal point for the rational number x/y:
function digit(x,y,n)
{
if (n == 0)
return Math.floor(x/y)%10;
return digit(10*(x%y),y,n-1);
}
It's recursive rather than iterative, and is not smart enough to detect cycles (the 10000th digit of 1/3 is obviously 3, but this keeps on going until it reaches the 10000th iteration), but it works at least until the stack runs out of memory.
Basically this works because of two facts:
the nth digit of x/y is the (n-1)th digit of 10x/y (example: the 6th digit of 1/7 is the 5th digit of 10/7 is the 4th digit of 100/7 etc.)
the nth digit of x/y is the nth digit of (x%y)/y (example: the 5th digit of 10/7 is also the 5th digit of 3/7)
We can tweak this to be an iterative routine and combine it with Floyd's cycle-finding algorithm (which I learned as the "rho" method from a Martin Gardner column) to get something that shortcuts this approach.
Here's a javascript function that computes a solution with this approach:
function digit(x,y,n,returnstruct)
{
function kernel(x,y) { return 10*(x%y); }
var period = 0;
var x1 = x;
var x2 = x;
var i = 0;
while (n > 0)
{
n--;
i++;
x1 = kernel(x1,y); // iterate once
x2 = kernel(x2,y);
x2 = kernel(x2,y); // iterate twice
// have both 1x and 2x iterations reached the same state?
if (x1 == x2)
{
period = i;
n = n % period;
i = 0;
// start again in case the nonrepeating part gave us a
// multiple of the period rather than the period itself
}
}
var answer=Math.floor(x1/y);
if (returnstruct)
return {period: period, digit: answer,
toString: function()
{
return 'period='+this.period+',digit='+this.digit;
}};
else
return answer;
}
And an example of running the nth digit of 1/700:
js>1/700
0.0014285714285714286
js>n=10000000
10000000
js>rs=digit(1,700,n,true)
period=6,digit=4
js>n%6
4
js>rs=digit(1,700,4,true)
period=0,digit=4
Same thing for 33/59:
js>33/59
0.559322033898305
js>rs=digit(33,59,3,true)
period=0,digit=9
js>rs=digit(33,59,61,true)
period=58,digit=9
js>rs=digit(33,59,61+58,true)
period=58,digit=9
And 122222/990000 (long nonrepeating part):
js>122222/990000
0.12345656565656565
js>digit(122222,990000,5,true)
period=0,digit=5
js>digit(122222,990000,7,true)
period=6,digit=5
js>digit(122222,990000,9,true)
period=2,digit=5
js>digit(122222,990000,9999,true)
period=2,digit=5
js>digit(122222,990000,10000,true)
period=2,digit=6
Here's another function that finds a stretch of digits:
// find digits n1 through n2 of x/y
function digits(x,y,n1,n2,returnstruct)
{
function kernel(x,y) { return 10*(x%y); }
var period = 0;
var x1 = x;
var x2 = x;
var i = 0;
var answer='';
while (n2 >= 0)
{
// time to print out digits?
if (n1 <= 0)
answer = answer + Math.floor(x1/y);
n1--,n2--;
i++;
x1 = kernel(x1,y); // iterate once
x2 = kernel(x2,y);
x2 = kernel(x2,y); // iterate twice
// have both 1x and 2x iterations reached the same state?
if (x1 == x2)
{
period = i;
if (n1 > period)
{
var jumpahead = n1 - (n1 % period);
n1 -= jumpahead, n2 -= jumpahead;
}
i = 0;
// start again in case the nonrepeating part gave us a
// multiple of the period rather than the period itself
}
}
if (returnstruct)
return {period: period, digits: answer,
toString: function()
{
return 'period='+this.period+',digits='+this.digits;
}};
else
return answer;
}
I've included the results for your answer (assuming that Javascript #'s didn't overflow):
js>digit(1,7,1,7,true)
period=6,digits=1428571
js>digit(1,7,601,607,true)
period=6,digits=1428571
js>1/7
0.14285714285714285
js>digit(2124679,214748367,214748300,214748400,true)
period=1759780,digits=20513882650385881630475914166090026658968726872786883636698387559799232373208220950057329190307649696
js>digit(122222,990000,100,110,true)
period=2,digits=65656565656
Ad hoc I have no good idea. Maybe continued fractions can help. I am going to think a bit about it ...
UPDATE
From Fermat's little theorem and because 39 is prime the following holds. (= indicates congruence)
10^39 = 10 (39)
Because 10 is coprime to 39.
10^(39 - 1) = 1 (39)
10^38 - 1 = 0 (39)
[to be continued tomorow]
I was to tiered to recognize that 39 is not prime ... ^^ I am going to update and the answer in the next days and present the whole idea. Thanks for noting that 39 is not prime.
The short answer for a/b with a < b and an assumed period length p ...
calculate k = (10^p - 1) / b and verify that it is an integer, else a/b has not a period of p
calculate c = k * a
convert c to its decimal represenation and left pad it with zeros to a total length of p
the i-th digit after the decimal point is the (i mod p)-th digit of the paded decimal representation (i = 0 is the first digit after the decimal point - we are developers)
Example
a = 3
b = 7
p = 6
k = (10^6 - 1) / 7
= 142,857
c = 142,857 * 3
= 428,571
Padding is not required and we conclude.
3 ______
- = 0.428571
7