代码高尔夫:新年烟花
2009年即将结束,经济和所有,我们将节省我们的钱,而不是购买昂贵的烟花,我们将在今年的ASCII艺术节庆祝。
挑战
给定一组烟花和时间,在那个时候拍下烟花的照片,然后把它拿到控制台上。
在除夕(UTC)午夜之前进入的最佳解决scheme将获得500名代表的奖励。 这是代码高尔夫,所以字符数量很重; 然而社区投票也是如此,我保留最好的/最酷的/最有创意的等等的最终决定。
input数据
请注意,我们的坐标系是从左到右,从下到上的,所以所有的烟花都是在y
坐标0(零)的情况下启动的。
input数据由表格的烟花组成
(x, speed_x, speed_y, launch_time, detonation_time)
哪里
-
x
是发射烟花的位置(列) -
speed_x
和speed_y
是发射时烟花的水平和垂直速度, -
launch_time
是这个烟火启动的时间点, -
detonation_time
时间是这个烟花引爆的时间点。
烟花数据可能在您的程序中被硬编码为五元组列表(或您的语言中的等同物),不计入您的人物数量。 但是,它必须很容易改变这些数据。
你可以做出以下假设:
- 有合理数量的烟花(比如less于一百)
- 对于每个烟花来说,所有的五个数字都是在一个合理的范围内的整数(比如,每个16位就足够了),
-
-20 <= x <= 820
-
-20 <= speed_x <= 20
-
0 < speed_y <= 20
-
launch_time >= 0
-
launch_time < detonation_time < launch_time + 50
单个附加的input数据是应该呈现的时间点。 这是一个非负整数,通过标准input或命令行参数(无论您select哪个)给您。
这个想法是(假设你的程序是一个名为firework.py
的python脚本),这个bash脚本给你一个不错的烟花animation:
#!/bin/bash I=0 while (( 1 )) ; do python firework.py $I I=$(( $I + 1 )) done
(随意把等效的.BAT文件放在这里)。
烟花的生命
烟花的生命如下:
- 在发射之前,可以忽略。
- 在发射时,火箭的位置
(x, 0)
和速度vector(speed_x, speed_y)
。 - 对于每个时间步,速度vector被添加到该位置。 牛顿定律有一点延伸,我们假定速度保持不变。
- 在引爆时间,火箭爆炸成九个火花。 在这个时间点上,所有九个火花都有相同的位置(这是火箭的位置,没有爆炸),但是它们的速度是不同的。 每个速度基于火箭的速度,
speed_x
或20加到speed_x
,speed_x
或10加到speed_y
。 这是九种可能的组合。 - 引爆时间之后,重力开始拉动:在每一个时间步中,从每个火花的
speed_y
减去恰好是2(2)的引力常数。 水平speed_x
保持不变。 - 对于引爆时间之后的每个时间步, 首先将速度vector添加到该位置, 然后从
speed_y
减去2。 - 当火花的
y
位置下降到零以下时,您可能会忘记它。
产量
我们想要的是在特定的时间点看烟花的照片。 我们只看帧0 <= x <= 789
和0 <= y <= 239
,将其映射为79×24的字符输出。
所以如果一个火箭或火花有位置(247,130),我们在第24栏(基于零的,所以它是第25列),第13行(从零开始,从底部开始计数,所以是23行 – 13 = 10,输出的第11行)。
取决于当前火箭的速度/火花:
- 如果运动是水平*,即
speed_y == 0 or abs(speed_x) / abs(speed_y) > 2
,则字符为“-
”。 - 如果运动是垂直*,即
speed_x == 0 or abs(speed_y) / abs(speed_x) > 2
,则字符为“|
”。 - 否则,运动是对angular的,而字符是“
\
”或“/
”(你会猜到正确的)。 - 如果相同的位置被多次绘制(即使它是相同的字符),我们把“
X
”代替。 所以假设你在(536, 119)
和(536, 119)
处有一个火花,你画一个“X
”,不pipe他们的速度如何。
*更新:这些是整数除法,因此斜率必须至less为3,或至多为1/3
输出(写入标准输出)是24行,每行都以换行符结尾。 尾随空格将被忽略,因此您可以但不需要填充到79的宽度。行不得超过79个字符(不包括换行符)。 所有内部空间必须是空格字符(ASCII 32)。
样本数据
烟花:
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)]
时间输出33:
\ | / / \ - | / - | - / \
时间77的输出:
\ \ X \
93时输出:
\ | / \ / / - - - \ \ / \ \
更新:我已经在0到99的时间上传期望的输出到firework.ü-wie-geek.de / NUMBER.html ,其中NUMBER是时间。 它包含debugging信息; 点击一个粒子看它的当前位置,速度等。是的,这是一个变音域。 如果你的浏览器不能处理(显然都不能堆栈溢出),请尝试firework.xn—wie-geek-p9a.de 。
另一个更新:正如下面的评论暗示的,现在YouTube上有更长的烟花。 它是用一个修改过的MizardX入口创build的 ,总共有170个烟花(是的,这比规范要求的多,但程序处理得很好)。 除了颜色,音乐和结束画面外,animation还可以通过此代码高尔夫的任何input重新创build。 所以,如果你足够喜欢享受ASCII艺术烟花(你知道你是):玩得开心,新年快乐!
下面是我在Python中的解决scheme:
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)
花时间从标准input,它有342个字符的好数字。 我仍然试图想像OP如何获得320:P
编辑:这是我可以得到的最好的,根据wc 322字符
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),
现在select了胜利者 – 祝贺胡安 – 这是我自己的解决scheme,Python中有304个字符:
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))
这并不是很快,因为对于79×24显示器中的每个点,它遍历所有的烟花,看看它们中的任何一个在这个点上是否可见。
这里是一个试图解释发生了什么的版本:
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'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)
如果您删除了最初的烟花声明,请将variables名称压缩为单个字符,并将空格压缩到最小值,则可以获得590个字符。
C:
删除所有不必要的空白(不包括烟花声明的632个字节):
#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);}}
这里是完全相同的代码添加空白为了可读性:
#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); } }
对于Python来说,@ MizardX的解决scheme很不错,但显然不是代码高级优化的 – 除了“不真正计数”前缀的333个字符,即:
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
(最后一个评论是我的一个小小的代码 – 辅助脚本的帮手,它使所有可行的名称机械地1个字符 – 它需要被告知什么名字不缩小;-),最短的我可以通过挤压空格是592个字符(足够接近590 @MizardX声明)。
拉出所有的中止(在代码高手的情绪下“重构”代码),在前缀后面(我用小写字母表示单个字符名称,我手动引入或replace,大写字母表示我的代码高手脚本自动replace):
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)
在460个字符的措施 – 这是减less130,即130/590 = 22%。
除了1个字符的名称和明显的方法来最小化间距外,关键的思想包括:单一/
分割(与Python 2中的ints相同)* if/else
expression式替代if/elif/else
语句,用一个genexp而不是一个带有append
的嵌套循环来extend
(允许删除一些空格和标点符号),而不是绑定到一个只出现一次的名称子expression式,绑定到一个名字子expression式,否则会重复(包括.extend
属性查找),分号而不是换行符(如果单独的行必须缩进,否则将换行符计为1个字符,则不存储)。
是的,可读性受到一些影响,但是在代码高尔夫中这并不令人惊讶;-)。
编辑 :更紧缩之后,我现在有一个更小的程序(相同的前缀):
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)
仍然是相同的输出,但现在360个字符 – 比我以前的解决scheme,我已经留下作为这个答案的第一部分(仍然远高于OP说,他说,他已经!
我已经利用了允许input时间值来自stdin的自由度( input
比inputsys
和使用sys.argv[1]
! – 要严格得多),消除了中间列表(w /扩展调用和它的最后一个循环),赞成新的函数g
,直接调用并更新K,我们去,find并删除了一些共同性,重构嵌套的if / elseexpression到一个复杂的(但更简洁;-)build设和嵌套列表的索引使用了v>2.9*w
比w==0 or v/w>2
更简洁的事实(并且总是在要考虑的值的范围内给出相同的结果)。
编辑 :将K(“屏幕图像”)制作成一维列表可节省26个字符,将以下解决scheme缩小到334(仍然高于OP的14倍,但是closures…!):
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),
在F#中完成了957个字符,它很丑陋,
烟花arrays:
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)]
剩余的代码
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
“漂亮”的代码:
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
完全被盗用新的和改进的逻辑重写。 这与我可以到Python的距离很近。 你可以看到F#的弱点不是针对ad hoc脚本,在这里我必须显式地将V和W转换为float,用丑陋的属性声明主函数来得到命令行参数,而且我必须引用.NET System.Console.Write获得一个漂亮的输出。
哦,好的锻炼,以学习一门语言。
这里是544字节的新代码:
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
哈斯克尔
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
几乎没有MizardX那么出色,如果你删除了f=…
声明,那么进入1068个字符,但是地狱,这很有趣。 我已经有机会和Haskell玩了一段时间了。
(稍微)漂亮的版本也可用 。
编辑:确认。 重新阅读,我不太满足规范:这个版本打印一个新的烟花显示屏幕,每次你按一个键,并要求^C
退出; 它不需要一个命令行参数并打印出相关的屏幕。
Perl的
假设烟花数据被定义为:
@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
压缩,它在433个字符。 (请参阅历史编辑)
这是基于多个以前的答案片断(主要是MizardX的),可以绝对改善。 拖延其他与工作有关的任务,这意味着我现在必须放弃。
原谅编辑 – 拉出所有我知道的技巧,这可以压缩到356字符:
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
$=
是一个特殊的Perlvariables(以及$%
, $-
和$?
),只能取整数值。 使用它消除了使用int
函数的需要。
FORTRAN 77
从史前语言部门,这是我的入口 – 在FORTRAN 77。
包括初始化,less量空格和一些不必要的空格在内的2570个字符,但我不认为它可能会为了简洁而获胜。 特别是因为例如每行中的6个前导空间是强制性的。
我把这个文件叫做fireworks.ftn
,然后用gfortran
在Linux系统上编译。
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
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;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}
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 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]
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 [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)