Code Golf: feux d’artifice du Nouvel An

L’année 2009 s’achève, et avec l’économie et tout, nous économiserons notre argent et au lieu d’acheter des feux d’artifice coûteux, nous célébrerons cette année dans l’art ASCII.

Le défi

À l’aide d’un feu d’artifice et d’une heure, prenez une photo du feu d’artifice à ce moment-là et attirez-le sur la console.

La meilleure solution saisie avant minuit le 31 décembre recevra une prime de 500 rep. C’est du golf de code, donc le nombre de caractères compte énormément; cependant, il en va de même pour les votes de la communauté et je me réserve la décision finale quant à ce qui est le meilleur / le plus cool / le plus créatif / etc.

Des données d’entrée

Notez que notre système de coordonnées est de gauche à droite, de bas en haut, de sorte que tous les feux d’artifice sont lancés à une coordonnée y de 0 (zéro).

Les données d’entrée sont des feux d’artifice de la forme

 (x, speed_x, speed_y, launch_time, detonation_time) 

  • x est la position (colonne) où le feu d’artifice est lancé,
  • speed_x et speed_y sont la vitesse horizontale et verticale du feu d’artifice au moment du lancement,
  • launch_time est le moment où ce feu d’artifice est lancé,
  • detonation_time est le moment où ce feu d’artifice explose.

Les données de feu d’artifice peuvent être codées en dur dans votre programme sous la forme d’une liste de 5 tuples (ou l’équivalent dans votre langue), sans compter le nombre de caractères. Il doit cependant être facile de modifier ces données.

Vous pouvez faire les hypothèses suivantes:

  • il y a une quantité raisonnable de feux d’artifice (disons moins de cent)
  • pour chaque feu d’artifice, les cinq nombres sont des nombres entiers compris dans une fourchette raisonnable (par exemple, 16 bits suffiraient pour chacun),
  • -20 <= x <= 820
  • -20 <= speed_x <= 20
  • 0 < speed_y <= 20
  • launch_time >= 0
  • launch_time < detonation_time < launch_time + 50

Le seul élément supplémentaire de données d’entrée est le sharepoint temps qui doit être rendu. C’est un entier non négatif qui vous est donné via une entrée standard ou un argument de ligne de commande (selon votre choix).

L’idée est que (en supposant que votre programme soit un script python appelé firework.py ), ce script bash vous donne une belle animation feu d’artifice:

 #!/bin/bash I=0 while (( 1 )) ; do python firework.py $I I=$(( $I + 1 )) done 

(n’hésitez pas à mettre le fichier .BAT équivalent ici).

La vie d’un feu d’artifice

La vie d’un feu d’artifice est la suivante:

  • Avant le lancement, il peut être ignoré.
  • Au moment du lancement, la fusée a la position (x, 0) et le vecteur vitesse (speed_x, speed_y) .
  • Pour chaque pas de temps, le vecteur vitesse est ajouté à la position. Avec un petit étirement appliqué aux lois de Newton, nous supposons que la vitesse rest constante.
  • Au moment de la détonation, la fusée explose en neuf étincelles. Les neuf étincelles ont la même position à ce moment-là (qui est la position que la fusée aurait, n’avait pas explosé), mais leur vitesse diffère. Chaque vitesse est basée sur la vitesse de la fusée, avec -20, 0 ou 20 ajoutés à speed_x et -10, 0 ou 10 ajoutés à speed_y . C’est neuf combinaisons possibles.
  • Après le temps de détonation, la gravité commence à tirer: à chaque pas de temps, la constante gravitationnelle, qui se trouve être 2 (deux), est soustraite de la speed_y de chaque étincelle_y. La speed_x horizontale_x rest constante.
  • Pour chaque pas de temps après l’heure de détonation, vous devez d’ abord append le vecteur vitesse à la position, puis soustraire 2 de speed_y .
  • Lorsque la position y une étincelle tombe en dessous de zéro, vous pouvez l’oublier.

Sortie

Ce que nous voulons, c’est une image du feu d’artifice telle qu’elle se présente à un moment donné. Nous ne regardons que la trame 0 <= x <= 789 et 0 <= y <= 239 , en la mappant à une sortie de 79×24 caractères.

Donc, si une fusée ou une étincelle a la position (247, 130), nous dessinons un caractère dans la colonne 24 (base zéro, donc c’est la 25ème colonne), ligne 13 (base zéro et en partant du bas, donc ligne 23) – 13 = 10, la 11ème ligne du résultat).

Le personnage dessiné dépend de la vitesse actuelle de la fusée / étincelle:

  • Si le mouvement est horizontal *, c’est-à-dire speed_y == 0 or abs(speed_x) / abs(speed_y) > 2 , le caractère est ” - “.
  • Si le mouvement est vertical *, c’est-à-dire speed_x == 0 or abs(speed_y) / abs(speed_x) > 2 , le caractère est ” | “.
  • Sinon, le mouvement est en diagonale et le caractère est ” \ ” ou ” / ” (vous allez deviner le bon).
  • Si la même position est dessinée plus d’une fois (même si c’est le même caractère), nous mettons ” X ” à la place. Donc, en supposant que vous avez une étincelle à (536, 119) et une à (531, 115) , vous dessinez un ” X “, indépendamment de leur vitesse.

* update: ce sont des divisions entières, donc la pente doit être d’au moins 3, ou au plus 1/3, respectivement

La sortie (écrite sur la sortie standard) est de 24 lignes, chacune terminée par un caractère de nouvelle ligne. Les espaces de fin sont ignorés, vous pouvez donc, sans y être obligé, appliquer une largeur de 79. Les lignes ne doivent pas dépasser 79 caractères (à l’exclusion de la nouvelle ligne). Tous les espaces intérieurs doivent être des espaces (ASCII 32).

Données d’échantillon

Feux d’artifice:

 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)] 

Sortie au temps 33:






        \ |  /                                                   


                                                       / \    

        - |  /                                                   




        - |  -                                                   


                                                       / \    





Sortie au temps 77:













                                             \                                  






                                                 \                              
                       X                                                        


                       \                                                        

Sortie au temps 93:




               \ |  /                                                        

               \ / /                                                        

               - - - \                                         




        \                                                                       







   / \ \            



Mise à jour: J’ai téléchargé la sortie attendue aux temps 0 à 99 dans firework.ü-wie-geek.de / NUMBER.html , où NUMBER est l’heure. Il comprend des informations de débogage; cliquez sur une particule pour voir sa position actuelle, sa vitesse, etc. Et oui, c’est un domaine truffé. Si votre navigateur ne peut pas gérer cela (car de toute évidence, Stack Overflow), essayez firework.xn—wie-geek-p9a.de .

Une autre mise à jour: Comme indiqué dans les commentaires ci-dessous, un feu d’artifice plus long est maintenant disponible sur YouTube . Il a été créé avec une version modifiée de l’entrée de MizardX , avec un nombre total de feux d’artifice de 170 (oui, c’est plus que la spécification demandée, mais le programme l’a bien traité). À l’exception de la couleur, de la musique et de l’écran de fin, l’animation peut être recréée par n’importe quelle entrée de ce golf de code. Donc, si vous êtes assez geek pour profiter d’un feu d’artifice ASCII (vous savez que vous êtes): Amusez-vous bien, et bonne année à tous!

Voici ma solution en 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) 

Prend le temps de la stdin et il a le bon nombre de 342 caractères. J’essaie toujours d’imaginer comment l’OP a obtenu 320: P

Edit: C’est le meilleur que je puisse obtenir, 322 caractères selon WC

 t=input() s=([' ']*79+['\n'])*24 def p(x,y,i,j): if 790>x>-1' ',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), 

Maintenant que le gagnant est choisi – félicitations à Juan – voici ma propre solution, 304 personnages en 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 

Ce n'est pas très rapide, car pour chaque sharepoint l'affichage 79x24, il parcourt tous les feux d'artifice pour voir si l'un d'entre eux est visible à ce stade.

Voici une version qui tente d'expliquer ce qui se passe:

 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 sortingck. 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) 

Si vous supprimez la déclaration Fireworks initiale, compressez les noms de variables en caractères uniques et les espaces au minimum, vous pouvez obtenir 590 caractères.

C:

Avec tous les espaces inutiles supprimés (632 octets à l’exclusion de la déclaration de feux d’artifice):

 #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=G[3]){a=tG[3];x=G[0]+G[1]*a;y=G[2]*a;if(t=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);}} 

Et voici exactement le même code avec des espaces ajoutés pour plus de lisibilité:

 #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); } } 

Pour Python, la solution de @ MizardX est intéressante, mais clairement pas optimisée par codegolf – à part le “ne compte pas vraiment” 333 caractères du préfixe, à savoir:

 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 

(le dernier commentaire est une aide pour un petit script de codegolf-aux qui rend mécaniquement tous les noms possibles de 1-char – il faut lui dire quels noms ne pas minimiser ;-), le plus court que je puisse faire en comprimant Les espaces sont de 592 caractères (assez proches des 590 revendications de @MizardX).

En tirant tous les arrêts (“refactorisation” du code dans une ambiance de codegolf), après le préfixe (j’ai utilisé des minuscules pour les noms à un seul caractère, je les introduit ou les remplace manuellement par des majuscules pour mes scripts codegolf-aux) substitué automatiquement):

 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 Z2 else'|'if W==0 or v/w>2 else '\\'if W*V<0 else'/' print '\n'.join(''.join(J)for J in K) 

qui mesure 460 caractères - soit une réduction de 130, soit 130/590 = 22%.

Au-delà des noms à 1 caractère et des moyens évidents de minimiser l’espacement, les idées clés sont les suivantes: single / for division (identique à // ints dans Python 2. *), expression if/else à la place de if/elif/else instruction if/elif/else extend avec un genexp plutôt qu'une boucle nestede avec append (permet de supprimer certains espaces et certaines ponctuations), sans liaison avec un nom sous-expressions qui n'apparaissent qu'une seule fois, se liant à un sous-expression qui serait répété (y compris le .extend recherche d'atsortingbuts), les points-virgules plutôt que les nouvelles lignes lorsque cela est possible (seulement si les lignes séparées doivent être indentées, sinon, en comptant une nouvelle ligne à 1 caractère, il n'y a pas de sauvegarde).

Oui, la lisibilité en souffre un peu, mais ce n’est guère surprenant dans le golf de code ;-).

Edit : après plus de resserrement, j'ai maintenant un programme plus petit (même préfixe):

 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 

Toujours la même sortie, mais maintenant 360 caractères - exactement 100 de moins que ma précédente solution, que j'ai laissée comme première partie de cette réponse (encore bien au-delà des 320 que l'OP dit avoir, pourtant! -).

J'ai profité du degré de liberté permettant à stdin de input valeur du temps d'entrée (l' input est beaucoup plus sys.argv[1] que l'importation de sys et l'utilisation de sys.argv[1] ! -), élimine la liste intermédiaire (avec les appels sys.argv[1] . et une boucle finale de celle-ci) en faveur de la nouvelle fonction g qui est appelée directement et met à jour K au fur et à mesure, trouve et supprime certaines similitudes, refait l’expression nestede if / else en un bâtiment compliqué (mais plus concis 😉 l'indexation des listes nestedes, utilisant le fait que v>2.9*w est plus concis que w==0 or v/w>2 (et donne toujours le même résultat dans la plage de valeurs à prendre en compte).

Edit : créer K ("image écran") dans une liste 1-D enregistre 26 caractères supplémentaires, réduisant la solution suivante à 334 (toujours 14 au-dessus des OP, mais fermant ...! -):

 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 

Fait en F # en 957 * caractères, et c’est laid comme péché:

Tableau de feux d’artifice:

 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)] 

Code restant

 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")) [] 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 "" [] let main args = screen (int(args.[0])) 0 

Complètement volé réécrit avec une nouvelle logique améliorée. C’est aussi proche que je pourrais arriver à Python. Vous pouvez voir la faiblesse de F # pas être orienté vers le script ad hoc ici, où je dois convertir explicitement V et W en un float, déclarer une fonction principale avec un atsortingbut moche pour obtenir les arguments de la ligne de commande, et je dois référencer le .NET System.Console.Write pour obtenir un joli résultat.

Eh bien, bon exercice pour apprendre une langue avec.

Voici le nouveau code, à 544 octets:

 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] [] 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(x+j*2*R,z*VR*(R-1)+i*R,W+j*2,V+i-2*R)|]do ge)) 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,[],[]) 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 

Pas aussi impressionnant que celui de MizardX, avec 1068 caractères si vous supprimez la déclaration f=… mais bon, c’était amusant. Cela fait un moment que j’ai eu la chance de jouer avec Haskell.

La version (légèrement) plus jolie est également disponible .

Edit: Ack. En relisant, je ne rencontre pas tout à fait la spécification: cette version imprime un nouvel écran de feu d’artifice chaque fois que vous appuyez sur une touche, et nécessite que ^C quitté; il ne prend pas d’argument de ligne de commande et imprime l’écran correspondant.

Perl

En supposant que les données de feux d’artifice sont définies comme suit:

 @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 

Compressé, il contient 433 caractères. (voir les modifications pour l'histoire)

Ceci est basé sur des morceaux de plusieurs réponses précédentes (principalement de MizardX) et peut certainement être amélioré. La culpabilité de procrastiner d'autres tâches liées à l'emploi signifie que je dois abandonner pour le moment.


Pardonnez la modification - en tirant tous les trucs que je connais, cela peut être compressé en 356 caractères:

 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 

$= est une variable Perl spéciale (avec $% , $- et $? ) qui ne peut prendre que des valeurs entières. L’utiliser élimine le besoin d’utiliser la fonction int .

FORTRAN 77

Du département des langues préhistoriques, voici mon entrée – en FORTRAN 77.

2570 caractères, y compris l’initialisation, une poignée d’espaces et des espaces inutiles, mais je ne pense pas que cela soit susceptible de gagner en brièveté. Surtout que, par exemple, 6 espaces de premier plan sur chaque ligne sont obligatoires.

J’ai appelé ce fichier fireworks.ftn et l’ gfortran compilé avec gfortran sur un système 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=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 -> [Ssortingng] frame specs time = foldl (applyFirework time) (replicate 24 (replicate 79 ' ')) specs applyFirework :: Int -> [Ssortingng] -> (Int,Int,Int,Int,Int) -> [Ssortingng] 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 :: [Ssortingng] -> ((Int,Int),(Int,Int)) -> [Ssortingng] 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)