Code Golf: New Year's Fireworks

2009 is drawing to a close, and with the economy and everyone, we will save our money and instead of buying expensive fireworks, this year we will celebrate in ASCII art.

A task

Given the set of fireworks and time, take a picture of the fireworks at this very time and draw it on the console.

The best solution, introduced before midnight on New Year's Eve (UTC), will receive a reward of 500 turnips. This is code golf, so the number of characters depends a lot; however, community voices do this, and I reserve the final decision as to which is best / cool / most creative, etc.

Input data

Please note that our coordinate system is from left to right, from bottom to top, so all fireworks start with y coordinate 0 (zero).

Input consists of form fireworks

 (x, speed_x, speed_y, launch_time, detonation_time) 

Where

  • x is the position (column) at which the fireworks are launched,
  • speed_x and speed_y - horizontal and vertical speed of the fireworks during startup,
  • launch_time is the moment this firework is launched,
  • detonation_time is the moment when this firework explodes.

Fireworks data can be hard-coded in your program as a list of 5 tuples (or the equivalent in your language), not counting your character. However, it should be easy to modify this data.

You can make the following assumptions:

  • there are enough fireworks (say, less than a hundred).
  • for each firework, all five numbers are integers in a reasonable range (for example, 16 bits will be enough for each of them),
  • -20 <= x <= 820
  • -20 <= speed_x <= 20
  • 0 < speed_y <= 20
  • launch_time >= 0
  • launch_time < detonation_time < launch_time + 50

The only additional part of the input is the time point that needs to be displayed. This is a non-negative integer that is provided to you using standard input or a command line argument (depending on what you choose).

The idea is that (if 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).

Firework Life

The life of the fireworks is as follows:

  • Before starting, it can be ignored.
  • At launch, the rocket has position (x, 0) and a velocity vector (speed_x, speed_y) .
  • For each time step, a velocity vector is added to the position. With a slight tension applied to Newton's laws, we assume that the velocity remains constant.
  • During detonation, a rocket explodes into nine sparks. All nine sparks have the same position at this point in time (this is the position that a rocket would have had if it had not exploded), but their speeds are different. Each speed is based on the speed of the rocket, with -20, 0 or 20 added to speed_x and -10, 0 or 10 added to speed_y . These are nine possible combinations.
  • After the detonation time, gravity begins to drag: with each time step, the gravitational constant, which turns out to be 2 (two), is subtracted from each spark speed_y . Horizontal speed_x remains constant.
  • For each time step after the detonation time, first add the velocity vector to the position speed_y then subtract 2 from speed_y .
  • When the position of the spark y drops below zero, you can forget about it.

Exit

We want the picture of the fireworks to look the way it looks at a given moment in time. We only look at the frame 0 <= x <= 789 and 0 <= y <= 239 , mapping it to the output of 79x24 characters.

So, if the rocket or spark has position (247, 130), we draw a character in column 24 (zero, so this is the 25th column), line 13 (based on zero and counting from the bottom, so line 23 - 13 = 10, 11th line of exit).

Which character gets the picture depends on the current speed of the rocket / spark:

  • If the movement is horizontal *, that is, speed_y == 0 or abs(speed_x) / abs(speed_y) > 2 , the symbol is " - ".
  • If the movement is vertical *, i.e. speed_x == 0 or abs(speed_y) / abs(speed_x) > 2 , the symbol " | ".
  • Otherwise, the movement is diagonal, and the symbol is " \ " or " / " (you guess the correct one).
  • If the same position is dialed more than once (even if it has the same character), we instead put " x ". Suppose you have a spark in (536, 119) and one in (531, 115) , you draw " x ", regardless of their speed.

* update: these are whole divisions, so the slope should be at least 3 or no more than 1/3, respectively

The output (written to standard output) is 24 lines, each of which ends with a newline. Missing spaces are ignored, so you can, but not need them, type in a width of 79. Lines can be no more than 79 characters (excluding a new line). All internal intervals must be spaces (ASCII 32).

Data examples

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                                                        


                       \                                                        

Conclusion at time 93:




               \ | |  /                                                        

               \ / /                                                        

               - - - \                                         




        \                                                                       







   / \ \            



Update: I downloaded the expected result from 0 to 99 to firework.ü-wie-geek.de / NUMBER.html , where NUMBER is the time. It includes debugging information; click on a particle to see its current position, speed, etc. And yes, this is the umlaut domain. If your browser cannot handle this (as obviously cannot overflow the stacks), try firework.xn---wie-geek-p9a.de .

Another update:. As shown in the comments below, longer fireworks are now available on YouTube . It was created with a modified version of MizardX ', with a total of 170 fireworks (yes, this is more than a request, but the program handled it gracefully). With the exception of color, music, and the end screen, the animation can be recreated using any entry in this golf course. So, if you are ugly enough to enjoy ASCII fireworks (you know what you are): have fun and a happy new year for everyone!

+63
language-agnostic
Dec 22 '09 at 15:22
source share
14 answers

Here is 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=tl;x+=i*T if t>=d:e=td;[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) 

It gets time from stdin and has a 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 characters according 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=tl;x+=i*T;e=td 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), 
+12
Dec 28 '09 at 17:27
source share

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[(tD,t>D,tL,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*Ks*(Z*sZu))/10)==(x,y)][:2]+[" ","X"])[::3][-1]for x in Q(79)) 

This is not very fast, because for each point on the 79x24 display it goes through all the fireworks to see if any of them are currently visible.

Here is a version that tries to explain what is happening:

 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, ie the rocket hasn't exploded yet, this is just [(0, 0)]; # otherwise it 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 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 
+9
Jan 01 '09 at 11:42
source share

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 delete the original fireworks declaration, compress the variable names to single characters and spaces to a minimum, you can get 590 characters.

+8
Dec 23 '09 at 15:57
source share

FROM

With the removal of all unnecessary spaces (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 GF[i] #define RP[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=tG[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=tG[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 is the same code with a space 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 GF[i] #define RP[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); } } 
+7
Dec 26 '09 at 15:42
source share

For Python, @MizardX's solution is good, but clearly not optimized for codegolf - except that there are "really no" 333 prefix characters, 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 an assistant for a small codegolf-aux script that makes all possible names 1-char mechanically - it needs to be told which names DO NOT be minimized ;-), the shortest I can make this decision, compressing spaces - 592 characters to statements 590 @MizardX).

Pulling all the stops ("refactoring" the code in the codegolf mood), I get it after the prefix (I used lowercase letters for the single-character names that I manually entered or replaced, in upper case for those who my codegolf -aux script is automatically replaced with):

 import sys Z=int(sys.argv[1]) Y=[] e=Y.extend for X,W,V,U,T in f: if Z>=U: z=ZU;X+=W*z if Z<T:e(((X,V*z,W,V),)) else:R=ZT;e((X+Q*R,z*VR*(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 460 characters - this is a decrease of 130, i.e. 130/590 = 22%.

In addition to 1-character names and obvious ways to minimize the interval, key ideas include: single / for division (the same as the more pleasant // for ints in Python 2. *), an if/else expression instead of the if/elif/else , extend with the xp gene, rather than a nested loop with append (allows you to remove some spaces and punctuation), without binding to name subexpressions that occur only once, binding to name subexpressions that (including the search for the .extend attribute), semicolons, not new lines where possible (only if separate lines should be about otherwise, counting the new line as 1 character, there is no saving).

Yes, readability suffers a bit, but this is hardly surprising in code golf; -).

Edit : after much more tightening, now I have a small 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=ZU;X+=W*z if Z<T:g(X,V*z,W,V) else:R=ZT;[g(X+Q*2*R,z*VR*(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) 

All the same conclusion, but now 360 characters - exactly 100 less than my previous solution, which I left as the first part of this answer (still much higher than the 320 OP says that it is, though!).

I took advantage of the degree of freedom that allows me to enter the input time value from stdin ( input much tougher than sys import and using sys.argv[1] ! -), I excluded the intermediate list (w / extend calls and the final loop) in favor of the new function g , which is called directly and updates K as we go, discover and remove some commonality, reorganize the nested if / else expression into a complex (but shorter ;-) creating and indexing nested lists, using the fact that v>2.9*w more brief than w==0 or v/w>2 (and always gives the same result as in the range values ​​that need to be taken into account).

Edit : turning K ("screen image") into a one-dimensional list saves another 26 characters, reducing the following solution to 334 (still 14 higher than OP, but closing ... -):

 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=ZU;X+=W*z if Z<T:g(X,V*z,W,V) else:R=ZT;[g(X+Q*2*R,z*VR*(R-1)+P*R,W+Q*2,V+P-2*R)for Q in a for P in a] print ''.join(K), 
+7
Dec 27 '09 at 19:02
source share

Made in F # in 957 * characters, and it is 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 tfr=(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 de (x,y,v,w)=C(M(fun(x,y,v,w)->[x,y,vd,w;x,y,v,w;x,y,v+d,w])[x,y,v,we;x,y,v,w;x,y,v,w+e]) let D trs=(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 tlfrs=( let(a,m)=L tf (M(fun(x,y,v,w,t)->x+v,y+w,v,w,t)r) let(b,c)=D tm (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)labc) 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 tl 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 stolen rewritten with new and improved logic. This is as close to Python as possible. You can see the weakness of F #, which is not intended for ad hoc scripts here, where I have to explicitly convert V and W to float, declare the main function with an ugly attribute to get command line arguments, and I have to reference the .NET System.Console. Write to get a good conclusion.

Well, good exercise to learn a language.

Here's the new code: 544 bytes:

 let Q ptf=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 ms= let Z=int s.[0] for (X,W,V,U,T) in F do( if Z>=U then let z,R=ZU,ZT 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*VR*(R-1)+i*R,W+j*2,V+i-2*R)|]do ge)) System.Console.Write K 0 
+7
Dec 28 '09 at 7:19
source share

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,[],[]) js 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)(ehw)++(concat.e ac.c((==t).b))x)(i-1) where x=egv kxy |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,ktu) n(x,y,_)(u,v,_) |z==EQ=compare xu |d=z where z=compare yv 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)) ox=x q _ y [] |y==23="" |d='\n':(q 0(y+1)[]) qvu((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)ut) p(_,_,v,w)=q 0 0((c zosortBy n)((elv)++(emw))) where z(x,y,_)=x>=0&&x<79&&y>=0 rx=do{z <- getChar;(putStr.p)x} s=e(rj i)[1..] main=foldr(>>)(return())s 

Not as impressive as MizardX, which comes in 1,068 characters, if you remove the ad f=… , but damn it was fun. It has been a while since I had the opportunity to play with Haskell.

A (slightly) more beautiful version is also available .

Edit: Ack. While re-reading, I do not quite meet the specifications: this version prints a new firework screen every time you press a key, and requires ^C to exit; it does not accept a command line argument and prints the corresponding screen.

+6
Dec 23 '09 at 19:41
source share

Perl

Assuming the fireworks data are 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 433 characters. (see edits for history)

This is based on fragments of several previous answers (mostly MizardX) and can definitely be improved. The guilt of delaying other work-related tasks means that I must refuse now.




Goodbye editing - pulling out all 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 $? ), which can only accept integer values. Using this method eliminates the need for an int function.

+5
Dec 29 '09 at 22:44
source share

FORTRAN 77

From the department of prehistoric languages, here my entry is in FORTRAN 77.

2570 characters, including initialization, a few spaces and some extra spaces, but I don't think this can win for brevity. Moreover, for example, 6 leading spaces in each line are mandatory.

I named this file fireworks.ftn and compiled it with gfortran on a Linux system.

  implicit integer(az) 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 
+3
01 . '09 17:08
source share

Haskell. 911 ; , 732 :

 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;pg} fst=i(at)(r 24(r 79' '))s atf(x,s,y,l,d)=if t<l then f else if t<d then cf((x+s*u,y*u),(s,y))else icf(map(v(td)(o(dl)(x,0)(s,y)))[(gs,hy)|g<-[id,(subtract 20),(+20)],h<-[id,(subtract 10),(+10)]])where u=tl v 0(x,y)(vx,vy)=((x,y),(vx,vy)) vt(x,y)(vx,vy)=v(t-1)(x+vx,y+vy)(vx,vy-2) ot(x,y)(vx,vy)=(x+(vx*t),y+(vy*t)) cf((x,y),(vx,vy))=if x<0||x>=z||y<0||y>=w then f else(take mf)++[(take nr)++[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=wy;n=x`div`10;m=s`div`10;r=f!!m;d=r!!n} 

:

 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 
+2
01 . '09 0:34
source share

Tcl8.5 913 , :

 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 dp @ up upvar 1 @ < append out @ _ foreach @ e info exists @ ? if : P {sdtl} {+ $s [* $d [- $t $l]]} : > x {= x} : d {P x X y Y} {up $P p = x [/ $x 10] = y [/ $y 10] = p($x,$y) [? [ep($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} {? {[ep($x,$y)]} {< $p($x,$y)} {< " "}} < "\n"} puts $out} : s {F t} {array set p {} _ {x XY ld} $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}}}}} rp} s $F [lindex $argv 0] 

. . , . , Forth-like:

:

 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] 
+2
01 . '09 10:40
source share
+1
23 . '09 3:39
source share

Clojure

, , 640 - :( , " " .

 (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 [xyuv dt g] (if (<= dt 0) [xyuv] (recur (+ xu) (+ yv) u (+ vg) (dec dt) g))) (defn pp [tf] (let [y 0 [xuvad] f r1 (rr xyuv (- (min td) a) 0)] (if (< ta) '() (if (< td) (list r1) (for [m '(-20 0 20) n '(-10 0 10)] (let [[xyuv] r1] (rr xy (+ um) (+ vn) (- td) -2))))))) (defn at [xyt] (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 [[xyuv] (first h)] (cond (or (zero? v) (> (* (/ uv) (/ uv)) 4)) \- (or (zero? u) (> (* (/ vu) (/ vu)) 4)) \| (= (neg? u) (neg? v)) \/ :else \\ ))))) (defn q [t] (doseq [r (range 23 -1 -1)] (doseq [c (range 0 80)] (print (g (at crt)))) (println))) (q 93) 
+1
01 . '09 21:28
source share
+1
03 . '09 15:29
source share



All Articles