language-agnostic

language agnostic - Code Golf: fuegos artificiales de fin de año



language-agnostic (14)

El año 2009 está llegando a su fin, y con la economía y todo, ahorraremos nuestro dinero y en lugar de comprar caros fuegos artificiales, celebraremos este año en arte ASCII.

El reto

Dado un conjunto de fuegos artificiales y un tiempo, tome una foto de los fuegos artificiales en ese momento y sáquelo a la consola.

La mejor solución ingresada antes de la medianoche en la víspera de Año Nuevo (UTC) recibirá una recompensa de 500 rep. Esto es código de golf, por lo que el número de personajes cuenta mucho; sin embargo, también lo hacen los votos de la comunidad, y me reservo la decisión final sobre qué es mejor / más fresco / más creativo / etc.

Datos de entrada

Tenga en cuenta que nuestro sistema de coordenadas es de izquierda a derecha, de abajo arriba, por lo que todos los fuegos artificiales se inician en una coordenada y de 0 (cero).

Los datos de entrada consisten en fuegos artificiales de la forma

(x, speed_x, speed_y, launch_time, detonation_time)

dónde

  • x es la posición (columna) donde se lanza el fuego artificial,
  • speed_x y speed_y son la velocidad horizontal y vertical de los fuegos artificiales en el momento del lanzamiento,
  • launch_time es el momento en que se lanza este fuego artificial,
  • detonation_time es el momento en que este fuego artificial detonará.

Los datos de fuegos artificiales pueden estar codificados en su programa como una lista de 5 tuplas (o el equivalente en su idioma), sin contar para el recuento de caracteres. Sin embargo, debe ser fácil cambiar esta información.

Puede hacer las siguientes suposiciones:

  • hay una cantidad razonable de fuegos artificiales (por ejemplo, menos de cien)
  • para cada fuegos artificiales, los cinco números son enteros dentro de un rango razonable (digamos, 16 bits serían suficientes para cada uno),
  • -20 <= x <= 820
  • -20 <= speed_x <= 20
  • 0 < speed_y <= 20
  • launch_time >= 0
  • launch_time < detonation_time < launch_time + 50

La única pieza adicional de datos de entrada es el punto de tiempo que se supone que se representará. Este es un entero no negativo que se le da a usted a través de entrada estándar o argumento de línea de comando (lo que usted elija).

La idea es que (suponiendo que tu programa sea un script de python llamado firework.py ) este script bash te da una bonita animación de fuegos artificiales:

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

(no dude en poner el archivo .BAT equivalente aquí).

La vida de un fuego artificial

La vida de un fuego artificial es la siguiente:

  • Antes del tiempo de lanzamiento, puede ser ignorado.
  • En el momento del lanzamiento, el cohete tiene la posición (x, 0) y el vector de velocidad (speed_x, speed_y) .
  • Para cada paso de tiempo, el vector de velocidad se agrega a la posición. Con un pequeño estiramiento aplicado a las leyes de Newton, suponemos que la velocidad se mantiene constante.
  • En el momento de la detonación, el cohete explota en nueve chispas. Las nueve chispas tienen la misma posición en este momento (que es la posición que tendría el cohete si no hubiera explotado), pero sus velocidades son diferentes. Cada velocidad se basa en la velocidad del cohete, con -20, 0 o 20 agregados a speed_x y -10, 0 o 10 agregados a speed_y . Eso es nueve combinaciones posibles.
  • Después del tiempo de detonación, la gravedad comienza a tirar: con cada paso de tiempo, la constante de gravitación, que resulta ser 2 (dos), se resta de la speed_y de cada speed_y . La speed_x horizontal permanece constante.
  • Para cada paso de tiempo después del tiempo de detonación, primero agrega el vector de velocidad a la posición, luego resta 2 de speed_y .
  • Cuando la posición y una chispa cae por debajo de cero, puede olvidarse de eso.

Salida

Lo que queremos es una imagen de los fuegos artificiales tal como se ve en el punto dado en el tiempo. Solo observamos el marco 0 <= x <= 789 y 0 <= y <= 239 , asignándolo a una salida de caracteres de 79x24.

Entonces, si un cohete o chispa tiene la posición (247, 130), dibujamos un personaje en la columna 24 (basado en cero, es la columna 25), fila 13 (basada en cero y contando desde abajo, entonces es la línea 23 - 13 = 10, la 11ª línea de la salida).

Qué personaje se dibuja depende de la velocidad actual del cohete / chispa:

  • Si el movimiento es horizontal *, es decir, speed_y == 0 or abs(speed_x) / abs(speed_y) > 2 , el carácter es " - ".
  • Si el movimiento es vertical *, es decir, speed_x == 0 or abs(speed_y) / abs(speed_x) > 2 , el carácter es " | ".
  • De lo contrario, el movimiento es diagonal, y el carácter es " / " o " / " (adivinará el correcto).
  • Si la misma posición se ve atraída más de una vez (incluso si es el mismo personaje), ponemos " X " en su lugar. Entonces, suponiendo que tiene una chispa en (536, 119) y una en (531, 115) , dibuja una " X ", independientemente de sus velocidades.

* actualización: estas son divisiones enteras, por lo que la pendiente debe ser de al menos 3, o como máximo 1/3, respectivamente

La salida (escrita a la salida estándar) es de 24 líneas, cada una terminada por un carácter de nueva línea. Los espacios finales se ignoran, por lo que puede, pero no es necesario, rellenar hasta un ancho de 79. Las líneas no pueden tener más de 79 caracteres (excluyendo la nueva línea). Todos los espacios interiores deben ser caracteres espaciales (ASCII 32).

Data de muestra

Fuegos artificiales:

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

Salida a tiempo 33:

/ | / / / - | / - | - / /

Salida en el tiempo 77:

/ / X /

Salida en el momento 93:

/ | / / / / - - - / / / / /

Actualización: he cargado la salida esperada en los tiempos 0 a 99 a firework.xn---wie-geek-p9a.de , donde NUMBER es la hora. Incluye información de depuración; haga clic en una partícula para ver su posición actual, velocidad, etc. Y sí, es un dominio umlaut. Si su navegador no puede manejar eso (como obviamente tampoco puede Stack Overflow), intente firework.xn---wie-geek-p9a.de .

Otra actualización: como se insinuó en los comentarios a continuación, ahora hay más fuegos artificiales disponibles en YouTube . Fue creado con una versión modificada de la entrada MizardX '' , con un conteo total de fuegos artificiales de 170 (sí, eso es más de lo que se pide, pero el programa lo manejó con gracia). Excepto por el color, la música y la pantalla final, la animación puede ser recreada por cualquier entrada a este código de golf. Por lo tanto, si eres lo suficientemente friki como para disfrutar de los fuegos artificiales de arte ASCII (ya sabes): Diviértete y ¡feliz año nuevo para todos!


Clojure

Unindented, without input output and unnecessary whitespace, it comes to 640 characters - exactly double the best value :( Thus, I''m not providing a "blank optimized" version in an attempt to win at brevity.

(def fw [ [628 6 6 3 33] [586 7 11 11 23] [185 -1 17 24 28] [189 14 10 50 83] [180 7 5 70 77] [538 -7 7 70 105] [510 -11 19 71 106] [220 -9 7 77 100] [136 4 14 80 91] [337 -13 20 106 128] ]) (defn rr [x y u v dt g] (if (<= dt 0) [x y u v] (recur (+ x u) (+ y v) u (+ v g) (dec dt) g))) (defn pp [t f] (let [y 0 [x u v a d] f r1 (rr x y u v (- (min t d) a) 0)] (if (< t a) ''() (if (< t d) (list r1) (for [m ''(-20 0 20) n ''(-10 0 10)] (let [[x y u v] r1] (rr x y (+ u m) (+ v n) (- t d) -2))))))) (defn at [x y t] (filter #(and (= x (quot (first %) 10)) (= y (quot (second %) 10))) (apply concat (map #(pp t %) fw)))) (defn g [h] (if (empty? h) /space (if (next h) /X (let [[x y u v] (first h)] (cond (or (zero? v) (> (* (/ u v) (/ u v)) 4)) /- (or (zero? u) (> (* (/ v u) (/ v u)) 4)) /| (= (neg? u) (neg? v)) // :else // ))))) (defn q [t] (doseq [r (range 23 -1 -1)] (doseq [c (range 0 80)] (print (g (at c r t)))) (println))) (q 93)


FORTRAN 77

Desde el departamento de idiomas prehistóricos, aquí está mi entrada - en FORTRAN 77.

2570 caracteres incluyendo la inicialización, un puñado de espacios y algunos espacios en blanco innecesarios, pero no creo que sea probable que gane por brevedad. Especialmente dado que, por ejemplo, 6 espacios principales en cada línea son obligatorios.

Llamé a este archivo fireworks.ftn y lo compilé con gfortran en un sistema Linux.

implicit integer(a-z) parameter (n=10) integer fw(5,n) / + 628, 6, 6, 3, 33, + 586, 7, 11, 11, 23, + 185, -1, 17, 24, 28, + 189, 14, 10, 50, 83, + 180, 7, 5, 70, 77, + 538, -7, 7, 70, 105, + 510, -11, 19, 71, 106, + 220, -9, 7, 77, 100, + 136, 4, 14, 80, 91, + 337, -13, 20, 106, 128 + / integer p(6, 1000) / 6000 * -1 / character*79 s(0:23) character z c Transform input do 10 r=1,n p(1, r) = 0 do 10 c=1,5 10 p(c+1, r) = fw(c, r) c Input end time read *, t9 c Iterate from 1 to end time do 62 t=1,t9 do 61 q=1,1000 if (p(1,q) .lt. 0 .or. t .lt. p(5,q)) goto 61 if (p(6,q).gt.0.and.t.gt.p(5,q) .or. t.gt.abs(p(6,q))) then p(1,q) = p(1,q) + p(4,q) p(2,q) = p(2,q) + p(3,q) endif if (t .lt. abs(p(6,q))) goto 61 if (t .gt. abs(p(6,q))) then p(4,q) = p(4,q) - 2 elseif (t .eq. p(6,q)) then c Detonation: Build 9 sparks do 52 m=-1,1 do 51 k=-1,1 c Find a free entry in p and fill it with a spark do 40 f=1,1000 if (p(1,f) .lt. 0) then do 20 j=1,6 20 p(j,f) = p(j,q) p(3,f) = p(3,q) + 20 * m p(4,f) = p(4,q) + 10 * k p(6,f) = -p(6,q) goto 51 endif 40 continue 51 continue 52 continue c Delete the original firework p(1,q) = -1 endif 61 continue 62 continue c Prepare output do 70 r=0,23 70 s(r) = '' '' do 80 q=1,1000 if (p(1,q) .lt. 0) goto 80 if (p(5,q) .gt. t9) goto 80 y = p(1,q) / 10 if (y .lt. 0 .or. y .gt. 23) goto 80 x = p(2,q) / 10 if (x .lt. 0 .or. x .gt. 79) goto 80 if (s(y)(x+1:x+1) .ne. '' '') then z = ''X'' elseif ((p(4,q) .eq. 0) .or. abs(p(3,q) / p(4,q)) .gt. 2) then z = ''-'' elseif ((p(3,q) .eq. 0) .or. abs(p(4,q) / p(3,q)) .gt. 2) then z = ''|'' elseif (sign(1, p(3,q)) .eq. sign(1, p(4,q))) then z = ''/'' else z = ''/' endif s(y)(x+1:x+1) = z 80 continue c Output do 90 r=23,0,-1 90 print *, s(r) end


Haskell

import Data.List f=[(628,6,6,3,33),(586,7,11,11,23),(185,-1,17,24,28),(189,14,10,50,83),(180,7,5,70,77),(538,-7,7,70,105),(510,-11,19,71,106),(220,-9,7,77,100),(136,4,14,80,91),(337,-13,20,106,128)] c=filter d=True e=map a(_,_,_,t,_)=t b(_,_,_,_,t)=t aa(_,y,_,_)=y ab(x,t,y,_,u)=(x,0,t,y,u) ac(x,y,t,u,_)=[(x,y,t+20,u+10),(x,y,t,u+10),(x,y,t-20,u+10),(x,y,t+20,u),(x,y,t,u),(x,y,t-20,u),(x,y,t+20,u-10),(x,y,t,u-10),(x,y,t-20,u-10)] g(x,y,t,u,v)=(x+t,y+u,t,u,v) h(x,y,t,u)=(x+t,y+u,t,u-2) i=(1,f,[],[]) j s 0=s j(t,u,v,w)i=j(t+1,c((/=t).a)u,c((> t).b)x++(e ab.c((==t).a))u,c((>0).aa)(e h w)++(concat.e ac.c((==t).b))x)(i-1) where x=e g v k x y |x==0=''|'' |3*abs y<=abs x=''-'' |3*abs x<=abs y=''|'' |(y<0&&x>0)||(y>0&&x<0)=''//' |d=''/'' l(x,y,t,u,_)=m(x,y,t,u) m(x,y,t,u)=(div x 10,23-div y 10,k t u) n(x,y,_)(u,v,_) |z==EQ=compare x u |d=z where z=compare y v o((x,y,t):(u,v,w):z) |x==u&&y==v=o((x,y,''X''):z) |d=(x,y,t):(o((u,v,w):z)) o x=x q _ y [] |y==23="" |d=''/n'':(q 0(y+1)[]) q v u((x,y,z):t) |u>22="" |v>78=''/n'':(q 0(u+1)((x,y,z):t)) |u/=y=''/n'':(q 0(u+1)((x,y,z):t)) |v/=x='' '':(q(v+1)u((x,y,z):t)) |d = z:(q(v+1)u t) p(_,_,v,w)=q 0 0((c z.o.sortBy n)((e l v)++(e m w))) where z(x,y,_)=x>=0&&x<79&&y>=0 r x=do{z <- getChar;(putStr.p)x} s=e(r.j i)[1..] main=foldr(>>)(return())s

No es tan impresionante como MizardX''s, con 1068 caracteres si eliminas la declaración f=… , pero diablos, fue divertido. Ha pasado un tiempo desde que tuve la oportunidad de jugar con Haskell.

La versión (un poco) más bonita también está disponible .

Editar: Ack. Al volver a leer, no alcanzo la especificación: esta versión imprime una nueva pantalla de fuegos artificiales cada vez que presiona una tecla y requiere ^C para salir; no toma un argumento de línea de comando e imprime la pantalla relevante.


Perl

Suponiendo que los datos de fuegos artificiales se definen como:

@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

Comprimido, tiene 433 caracteres. (ver ediciones para el historial)

Esto se basa en piezas de respuestas anteriores múltiples (principalmente MizardX) y definitivamente se puede mejorar. La culpa de postergar otras tareas relacionadas con el trabajo significa que tengo que darme por vencido por el momento.

Perdona la edición - sacando todos los trucos que sé, esto se puede comprimir a 356 caracteres:

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

$= es una variable especial de Perl (junto con $% , $- y $? ) que solo puede tomar valores enteros. Usarlo elimina la necesidad de usar la función int .


Ahora que se elige al winner , felicitaciones a Juan, esta es mi propia solución, 304 personajes 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[(t-D,t>D,t-L,G%3*20-20,G/3*10-10)for G in[Q(9),[4]][t<D]]for h,v in[[P+H,u+V-2*s*Z]]if((X+H*K+P*s)/10,23-(V*K-s*(Z*s-Z-u))/10)==(x,y)][:2]+[" ","X"])[::3][-1]for x in Q(79))

Esto no es realmente rápido, porque para cada punto en la pantalla de 79x24, pasa por todos los fuegos artificiales para ver si alguno de ellos es visible en este momento.

Aquí hay una versión que trata de explicar lo que está pasando:

t=input() Q=range for y in Q(24): line = "" for x in Q(79): chars = [] # will hold all characters that should be drawn at (x, y) for X,H,V,L,D in F: # loop through the fireworks s = t - D Z = t > D K = t - L # if t < D, i.e. the rocket hasn''t exploded yet, this is just [(0, 0)]; # otherwise it''s all combinations of (-20, 0, 20) for x and (-10, 0, 10) speed_deltas = [(G % 3 * 20 - 20, G / 3 * 10 -10) for G in [Q(9), [4]][t < D]] for P, u in speed_deltas: if x == (X + H*K + P*s)/10 and y == 23 - (V*K - s*(Z*s - Z - u))/10: # the current horizontal and vertical speed of the particle h = P + H v = u + V - 2*s*Z # this is identical to (but shorter than) abs(h) >= 3 * abs(v) is_horizontal = h*h >= 9*v*v is_vertical = v*v >= 9*h*h is_northeast_southwest = h*v > 0 # a shorter way of saying # char_index = (3 if is_horizontal else 2 if is_vertical else 1 # if is_northeast_southwest else 0) char_index = 3 * is_horizontal or 2 * is_vertical or is_northeast_southwest chars.append("///|-"[char_index]) # chars now contains all characters to be drawn to this point. So we have # three possibilities: If chars is empty, we draw a space. If chars has # one element, that''s what we draw. And if chars has more than one element, # we draw an "X". actual_char = (chars[:2] + [" ", "X"])[::3][-1] # Yes, this does the trick. line += actual_char print line


Aquí está mi solución 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=t-l;x+=i*T if t>=d:e=t-d;[p(x+X*e,j*T+e*(Y-e+1),i+X,j+Y-2*e)for X in -20,0,20 for Y in -10,0,10] elif t>=l:p(x,j*T,i,j) print ''''.join(s)

Toma el tiempo del stdin y tiene una buena cantidad de 342 caracteres. Todavía estoy tratando de imaginar cómo el OP obtuvo 320: P

Editar: Esto es lo mejor que pude conseguir, 322 caracteres de acuerdo con el wc

t=input() s=(['' '']*79+[''/n''])*24 def p(x,y,i,j): if 790>x>-1<y<240:p=x/10+(23-y/10)*80;I=abs(i);J=abs(j);s[p]=''X-|///''[[s[p]>'' '',I>=3*J,J>=3*I,i*j<0,1].index(1)] for x,i,j,l,d in c: T=t-l;x+=i*T;e=t-d if t>=d:[p(x+X*e,j*T+e*(Y-e+1),i+X,j+Y-2*e)for X in-20,0,20for Y in-10,0,10] elif t>=l:p(x,j*T,i,j) print''''.join(s),


Hecho en F # en 957 * caracteres, y es feo como sin:

Matriz de fuegos artificiales:

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

Código restante

let M=List.map let C=List.concat let P=List.partition let L t f r=(let s=P(fun(_,_,_,u,_)->not(t=u))f (fst s, r@(M(fun(x,v,w,_,t)->x,0,v,w,t)(snd s)))) let X d e (x,y,v,w)=C(M(fun(x,y,v,w)->[x,y,v-d,w;x,y,v,w;x,y,v+d,w])[x,y,v,w-e;x,y,v,w;x,y,v,w+e]) let D t r s=(let P=P(fun(_,_,_,_,u)->not(t=u))r (fst P,s@C(M(fun(x,y,v,w,_)->(X 20 10(x,y,v,w)))(snd P)))) let rec E t l f r s=( let(a,m)=L t f (M(fun(x,y,v,w,t)->x+v,y+w,v,w,t)r) let(b,c)=D t m (M(fun(x,y,v,w)->x+v,y+w,v,w-2)s) if(t=l)then(a,b,c)else E(t+1)l a b c) let N=printf let G t=( let(f,r,s)=E 0 t F [] [] let os=s@(M(fun(x,y,v,w,_)->(x,y,v,w))r) for y=23 downto 0 do ( for x=0 to 79 do ( let o=List.filter(fun(v,w,_,_)->((v/10)=x)&&((w/10)=y))os let l=o.Length if l=0 then N" " elif l=1 then let(_,_,x,y)=o.Head N( if y=0||abs(x)/abs(y)>2 then"-" elif x=0||abs(y)/abs(x)>2 then"|" elif y*x>0 then"/" else"//") elif o.Length>1 then N"X") N"/n")) [<EntryPointAttribute>] let Z a= G (int(a.[0])) 0

Código "Pretty":

let fxs = [(628,6,6,3,33);(586,7,11,11,23);(185,-1,17,24,28);(189,14,10,50,83);(180,7,5,70,77);(538,-7,7,70,105);(510,-11,19,71,106);(220,-9,7,77,100);(136,4,14,80,91);(337,-13,20,106,128)] let movs xs = List.map (fun (x, y, vx, vy) -> (x + vx, y + vy, vx, vy-2)) xs let movr xs = List.map (fun (x, y, vx, vy, dt) -> (x + vx, y + vy, vx, vy, dt)) xs let launch t fs rs = let split = List.partition(fun (lx, sx, sy, lt, dt) -> not (t = lt)) fs (fst split, rs @ (List.map(fun (lx, sx, sy, lt, dt) -> (lx, 0, sx, sy, dt)) (snd split))) let split dx dy (x,y,sx,sy) = List.concat (List.map (fun (x,y,sx,sy)->[(x,y,sx-dx,sy);(x,y,sx,sy);(x,y,sx+dx,sy)]) [(x,y,sx,sy-dy);(x,y,sx,sy);(x,y,sx,sy+dy)]) let detonate t rs ss = let tmp = List.partition (fun (x, y, sx, sy, dt) -> not (t = dt)) rs (fst tmp, ss @ List.concat (List.map(fun (x, y, sx, sy, dt) -> (split 20 10 (x, y, sx, sy))) (snd tmp))) let rec simulate t l fs rs ss = let (nfs, trs) = launch t fs (movr rs) let (nrs, nss) = detonate t trs (movs ss) if (t = l) then (nfs,nrs,nss) else simulate (t+1) l nfs nrs nss let screen t = let (fs, rs, ss) = simulate 0 t fxs [] [] let os = ss @ (List.map(fun (x, y, sx, sy,_) -> (x, y, sx, sy)) rs) for y = 23 downto 0 do for x = 0 to 79 do let o = List.filter(fun (px,py,_,_)->((px/10)=x) && ((py/10)=y)) os if o.Length = 0 then printf " " elif o.Length = 1 then let (_,_,sx,sy) = o.Head printf ( if sy = 0 || abs(sx) / abs(sy) > 2 then "-" elif sx = 0 || abs(sy) / abs(sx) > 2 then "|" elif sy * sx > 0 then "/" else"//" ) elif o.Length > 1 then printf "X" printfn "" [<EntryPointAttribute>] let main args = screen (int(args.[0])) 0

Completamente robado reescrito con lógica nueva y mejorada. Esto es lo más cerca que pude llegar a Python. Puede ver la debilidad de F # no estar orientado hacia scripts ad hoc aquí, donde tengo que convertir explícitamente V y W en un flotante, declaro una función principal con un atributo feo para obtener los argumentos de línea de comando, y tengo que hacer referencia al .NET System.Console.Write para obtener una salida bonita.

Bueno, buen ejercicio para aprender un idioma.

Aquí está el nuevo código, a 544 bytes:

let Q p t f=if p then t else f let K=[|for i in 1..1920->Q(i%80>0)'' ''''/n''|] let g(X,S,W,V)= if(X>=0&&X<790&&S>=0&&S<240)then( let (j,v,w)=(80*(23-S/10)+X/10,abs(float V),abs(float W)) Array.set K j (Q(K.[j]='' '')(Q(w>2.9*v)''-''(Q(v>2.9*w)''|''(Q(W*V>0)''/''''//')))''X'')) let a=[-10;0;10] [<EntryPointAttribute>] let m s= let Z=int s.[0] for (X,W,V,U,T) in F do( if Z>=U then let z,R=Z-U,Z-T let x=X+W*z if(Z<T)then(g(x,V*z,W,V))else(for e in[|for i in a do for j in a->(x+j*2*R,z*V-R*(R-1)+i*R,W+j*2,V+i-2*R)|]do g e)) System.Console.Write K 0


Para Python, la solución de @MizardX es agradable, pero claramente no optimizada para codegolf, además del "no cuenta realmente" 333 caracteres del prefijo, a saber:

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

(el último comentario es un ayudante para una pequeña secuencia de comandos codegolf-aux que hace que todos los nombres posibles sean de 1 char mecánicamente; necesita que se le diga qué nombres NO para minimizar ;-), lo más corto que pueda hacer esa solución es apretando el espacio en blanco tiene 592 caracteres (lo suficientemente cerca de los 590 reclamos @MizardX).

Tirando de todas las paradas ("refactorizando" el código en un estado de ánimo codegolf), obtengo, después del prefijo (He usado minúsculas para nombres de un solo carácter que estoy introduciendo o sustituyendo manualmente, en mayúsculas para aquellos mi script codegolf-aux sustituido automáticamente):

import sys Z=int(sys.argv[1]) Y=[] e=Y.extend for X,W,V,U,T in f: if Z>=U: z=Z-U;X+=W*z if Z<T:e(((X,V*z,W,V),)) else:R=Z-T;e((X+Q*R,z*V-R*(R-1)+P*R,W+Q,V+P-2*R)for Q in(-20,0,20)for P in(-10,0,10)) K=[79*['' '']for S in range(24)] for X,S,W,V in Y: X,S=X/10,S/10 if(0<=X<79)&(0<=S<24): J=K[23-S];v=abs(V);w=abs(W) J[X]=''X''if J[X]!='' ''else''-''if V==0 or w/v>2 else''|''if W==0 or v/w>2 else ''//'if W*V<0 else''/'' print ''/n''.join(''''.join(J)for J in K)

que mide a 460 caracteres, es una reducción de 130, es decir, 130/590 = 22%.

Más allá de los nombres de 1 personaje y las formas obvias de minimizar el espaciado, las ideas clave incluyen: single / for division (igual que el más bonito // para ints en Python 2. *), una expresión if/else en lugar de if/elif/else sentencia if/elif/else , extend con un genexp en lugar de un bucle anidado con append (permite la eliminación de algunos espacios y signos de puntuación), no vinculante a subexpresiones de nombre que se producen una sola vez, vinculando a un nombre subexpresiones que de lo contrario se repetirían (incluido el .extend búsqueda de atributos), punto y coma en lugar de líneas nuevas cuando sea posible (solo si las líneas separadas tendrían que sangrarse, de lo contrario, contando una nueva línea como 1 carácter, no hay guardado).

Sí, la legibilidad sufre un poco, pero eso no es sorprendente en el código de golf ;-).

Editar : después de mucho más ajuste, ahora tengo un programa más pequeño (mismo prefijo):

Z=input() K=[79*['' '']for S in range(24)];a=-10,0,10 def g(X,S,W,V): X/=10;S/=10 if(0<=X<79)&(0<=S<24):J=K[23-S];v=abs(V);w=abs(W);J[X]=[[[''///'[W*V<0],''|''][v>2.9*w],''-''][w>2.9*v],''X''][J[X]!='' ''] for X,W,V,U,T in f: if Z>=U: z=Z-U;X+=W*z if Z<T:g(X,V*z,W,V) else:R=Z-T;[g(X+Q*2*R,z*V-R*(R-1)+P*R,W+Q*2,V+P-2*R)for Q in a for P in a] print''/n''.join(''''.join(J)for J in K)

Sigue siendo el mismo producto, pero ahora tiene 360 ​​caracteres, exactamente 100 menos que mi solución anterior, que me queda como la primera parte de esta respuesta (¡todavía muy por encima de los 320 que el OP dice que tiene, sin embargo! -).

He aprovechado el grado de libertad que permite que el valor del tiempo de entrada proceda de stdin (la input es mucho más ajustada que la importación de sys y el uso de sys.argv[1] ! -), eliminó la lista intermedia (con las llamadas extendidas y un bucle final) en favor de la nueva función g que recibe llamadas directas y actualiza K según avanzamos, encuentra y elimina algunas características comunes, refactoriza la expresión anidada if / else en un edificio complicado (pero más conciso ;-) y la indexación de listas anidadas, utilizó el hecho de que v>2.9*w es más conciso que w==0 or v/w>2 (y siempre da el mismo resultado en el rango de valores que deben considerarse).

Editar : hacer K (la "imagen de pantalla") en una lista en 1-D ahorra otros 26 caracteres, reduciendo la siguiente solución a 334 (todavía 14 por encima de los OP, pero cerrando ...! -):

Z=input() K=list(24*('' ''*79+''/n'')) a=-10,0,10 def g(X,S,W,V): if(0<=X<790)&(0<=S<240):j=80*(23-S/10)+X/10;v=abs(V);w=abs(W);K[j]=[[[''///'[W*V<0],''|''][v>2.9*w],''-''][w>2.9*v],''X''][K[j]!='' ''] for X,W,V,U,T in f: if Z>=U: z=Z-U;X+=W*z if Z<T:g(X,V*z,W,V) else:R=Z-T;[g(X+Q*2*R,z*V-R*(R-1)+P*R,W+Q*2,V+P-2*R)for Q in a for P in a] print ''''.join(K),


DO:

Con todo el espacio en blanco innecesario eliminado (632 bytes excluyendo la declaración de fuegos artificiales):

#define N 10 int F[][5]={628,6,6,3,33,586,7,11,11,23,185,-1,17,24,28,189,14,10,50,83,180,7,5,70,77,538,-7,7,70,105,510,-11,19,71,106,220,-9,7,77,100,136,4,14,80,91,337,-13,20,106,128}; #define G F[i] #define R P[p] g(x,y){if(y==0||abs(x)/abs(y)>2)return 45;if(x==0||abs(y)/abs(x)>2)return''|'';if(x*y<0)return 92;return 47;}main(int A,char**B){int a,b,c,C[24][79]={},d,i,j,p=0,P[N*9][3],Q,t=atoi(B[1]),x,y;for(i=0;i<N;i++){if(t>=G[3]){a=t-G[3];x=G[0]+G[1]*a;y=G[2]*a;if(t<G[4]){R[0]=x;R[1]=y;R[2]=g(G[1],G[2]);p++;}else{b=t-G[4];y-=b*(b-1);for(c=-20;c<=20;c+=20){for(d=-10;d<=10;d+=10){R[0]=x+c*b;R[1]=y+d*b;R[2]=g(G[1]+c,G[2]+d-2*b);p++;}}}}}Q=p;for(p=0;p<Q;p++){x=R[0]/10;y=R[1]/10;if(R[0]>=0&&x<79&&R[1]>=0&&y<24)C[y][x]=C[y][x]?88:R[2];}for(i=23;i>=0;i--){for(j=0;j<79;j++)putchar(C[i][j]?C[i][j]:32);putchar(10);}}

Y aquí está exactamente el mismo código con espacios en blanco añadidos para la legibilidad:

#define N 10 int F[][5] = { 628, 6, 6, 3, 33, 586, 7, 11, 11, 23, 185, -1, 17, 24, 28, 189, 14, 10, 50, 83, 180, 7, 5, 70, 77, 538, -7, 7, 70, 105, 510, -11, 19, 71, 106, 220, -9, 7, 77, 100, 136, 4, 14, 80, 91, 337, -13, 20, 106, 128 }; #define G F[i] #define R P[p] g(x, y) { if(y == 0 || abs(x)/abs(y) > 2) return 45; if(x == 0 || abs(y)/abs(x) > 2) return ''|''; if(x*y < 0) return 92; return 47; } main(int A, char**B){ int a, b, c, C[24][79] = {}, d, i, j, p = 0, P[N*9][3], Q, t = atoi(B[1]), x, y; for(i = 0; i < N; i++) { if(t >= G[3]) { a = t - G[3]; x = G[0] + G[1]*a; y = G[2]*a; if(t < G[4]) { R[0] = x; R[1] = y; R[2] = g(G[1], G[2]); p++; } else { b = t - G[4]; y -= b*(b-1); for(c = -20; c <= 20; c += 20) { for(d =- 10; d <= 10; d += 10) { R[0] = x + c*b; R[1] = y + d*b; R[2] = g(G[1] + c, G[2] + d - 2*b); p++; } } } } } Q = p; for(p = 0; p < Q; p++) { x = R[0]/10; y = R[1]/10; if(R[0] >= 0 && x < 79 && R[1] >= 0 && y < 24) C[y][x] = C[y][x] ? 88 : R[2]; } for(i = 23; i >= 0; i--) { for(j = 0; j < 79; j++) putchar(C[i][j] ? C[i][j] : 32); putchar(10); } }


Pitón:

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 elimina la declaración inicial de fuegos artificiales, comprima nombres de variables en caracteres individuales y espacios en blanco a un mínimo, puede obtener 590 caracteres.



First draft in Tcl8.5 913 bytes excluding fireworks definition:

set F { 628 6 6 3 33 586 7 11 11 23 185 -1 17 24 28 189 14 10 50 83 180 7 5 70 77 538 -7 7 70 105 510 -11 19 71 106 220 -9 7 77 100 136 4 14 80 91 337 -13 20 106 128 } namespace import tcl::mathop::* proc @ {a args} {interp alias {} $a {} {*}$args} @ : proc @ = set @ D d p @ up upvar 1 @ < append out @ _ foreach @ e info exists @ ? if : P {s d t l} {+ $s [* $d [- $t $l]]} : > x {= x} : d {P x X y Y} {up $P p = x [/ $x 10] = y [/ $y 10] = p($x,$y) [? [e p($x,$y)] {> X} elseif { $Y==0||abs($X)/abs($Y)>2} {> -} elseif { $X==0||abs($Y)/abs($X)>2} {> |} elseif { $X*$Y<0} {> //} {> /}]} : r {P} {up $P p = out "" for {= y 23} {$y >= 0} {incr y -1} { for {= x 0} {$x < 79} {incr x} {? {[e p($x,$y)]} {< $p($x,$y)} {< " "}} < "/n"} puts $out} : s {F t} {array set p {} _ {x X Y l d} $F {? {$t >= $l} {? {$t < $d} {= x [P $x $X $t $l] = y [P 0 $Y $t $l] D $x $X $y $Y} {= x [P $x $X $d $l] = y [P 0 $Y $d $l] = v [- $t $d] _ dx {-20 0 20} {_ dy {-10 0 10} {= A [+ $X $dx] = B [- [+ $Y $dy] [* 2 $v]] = xx [P $x $A $v 0] = yy [P $y $B $v 0] D $xx $A $yy $B}}}}} r p} s $F [lindex $argv 0]

Optimized to the point of unreadability. Still looking for room to improve. Most of the compression basically uses command aliasing substituting single characters for command names. For example, function definitions are done using Forth-like : syntax.

Here''s the uncompressed version:

namespace import tcl::mathop::* set fireworks { 628 6 6 3 33 586 7 11 11 23 185 -1 17 24 28 189 14 10 50 83 180 7 5 70 77 538 -7 7 70 105 510 -11 19 71 106 220 -9 7 77 100 136 4 14 80 91 337 -13 20 106 128 } proc position {start speed time launch} { + $start [* $speed [- $time $launch]] } proc give {x} {return $x} proc draw {particles x speedX y speedY} { upvar 1 $particles p set x [/ $x 10] set y [/ $y 10] set p($x,$y) [if [info exists p($x,$y)] { give X } elseif {$speedY == 0 || abs(double($speedX))/abs($speedY) > 2} { give - } elseif {$speedX == 0 || abs(double($speedY))/abs($speedX) > 2} { give | } elseif {$speedX * $speedY < 0} { give // } else { give / } ] } proc render {particles} { upvar 1 $particles p set out "" for {set y 23} {$y >= 0} {incr y -1} { for {set x 0} {$x < 79} {incr x} { if {[info exists p($x,$y)]} { append out $p($x,$y) } else { append out " " } } append out "/n" } puts $out } proc show {fireworks time} { array set particles {} foreach {x speedX speedY launch detonate} $fireworks { if {$time >= $launch} { if {$time < $detonate} { set x [position $x $speedX $time $launch] set y [position 0 $speedY $time $launch] draw particles $x $speedX $y $speedY } else { set x [position $x $speedX $detonate $launch] set y [position 0 $speedY $detonate $launch] set travel [- $time $detonate] foreach dx {-20 0 20} { foreach dy {-10 0 10} { set speedXX [+ $speedX $dx] set speedYY [- [+ $speedY $dy] [* 2 $travel]] set xx [position $x $speedXX $travel 0] set yy [position $y $speedYY $travel 0] draw particles $xx $speedXX $yy $speedYY } } } } } render particles } show $fireworks [lindex $argv 0]


Here''s a smaller Haskell implementation. It''s 911 characters; minus the fireworks definition, it''s 732 characters:

import System z=789 w=239 r=replicate i=foldl main=do{a<-getArgs;p(f[(628,6,6,3,33),(586,7,11,11,23),(185,-1,17,24,28),(189,14,10,50,83),(180,7,5,70,77),(538,-7,7,70,105),(510,-11,19,71,106),(220,-9,7,77,100),(136,4,14,80,91),(337,-13,20,106,128)](read(a!!0)::Int));} p[]=return() p(f:g)=do{putStrLn f;p g} f s t=i(a t)(r 24(r 79'' ''))s a t f(x,s,y,l,d)=if t<l then f else if t<d then c f((x+s*u,y*u),(s,y))else i c f(map(v(t-d)(o(d-l)(x,0)(s,y)))[(g s,h y)|g<-[id,(subtract 20),(+20)],h<-[id,(subtract 10),(+10)]])where u=t-l v 0(x,y)(vx,vy)=((x,y),(vx,vy)) v t(x,y)(vx,vy)=v(t-1)(x+vx,y+vy)(vx,vy-2) o t(x,y)(vx,vy)=(x+(vx*t),y+(vy*t)) c f((x,y),(vx,vy))=if x<0||x>=z||y<0||y>=w then f else(take m f)++[(take n r)++[if d/='' ''then ''x''else if vy==0||abs(vx`div`vy)>2 then ''-''else if vx==0||abs(vy`div`vx)>2 then ''|''else if vx*vy>=0 then ''/''else ''//']++(drop(n+1)r)]++(drop(m+1)f)where{s=w-y;n=x`div`10;m=s`div`10;r=f!!m;d=r!!n}

Here''s the non-compressed version for the curious:

import System sizeX = 789 sizeY = 239 main = do args <- getArgs printFrame (frame fireworks (read (args !! 0) :: Int)) where fireworks = [ (628, 6, 6, 3, 33), (586, 7, 11, 11, 23), (185, -1, 17, 24, 28), (189, 14, 10, 50, 83), (180, 7, 5, 70, 77), (538, -7, 7, 70, 105), (510, -11, 19, 71, 106), (220, -9, 7, 77, 100), (136, 4, 14, 80, 91), (337, -13, 20, 106, 128)] printFrame :: [String] -> IO () printFrame [] = return () printFrame (f:fs) = do putStrLn f printFrame fs frame :: [(Int,Int,Int,Int,Int)] -> Int -> [String] frame specs time = foldl (applyFirework time) (replicate 24 (replicate 79 '' '')) specs applyFirework :: Int -> [String] -> (Int,Int,Int,Int,Int) -> [String] applyFirework time frame (x,sx,sy,lt,dt) = if time < lt then frame else if time < dt then drawChar frame ((x + sx * timeSinceLaunch, sy * timeSinceLaunch), (sx,sy)) else foldl drawChar frame ( map ( posVelOverTime (time - dt) (posOverTime (dt - lt) (x,0) (sx, sy)) ) [ (fx sx, fy sy) | fx <- [id,(subtract 20),(+20)], fy <- [id,(subtract 10),(+10)] ] ) where timeSinceLaunch = time - lt posVelOverTime :: Int -> (Int,Int) -> (Int,Int) -> ((Int,Int),(Int,Int)) posVelOverTime 0 (x,y) (vx,vy) = ((x,y),(vx,vy)) posVelOverTime time (x,y) (vx,vy) = posVelOverTime (time - 1) (x+vx, y+vy) (vx, vy - 2) posOverTime :: Int -> (Int,Int) -> (Int,Int) -> (Int,Int) posOverTime time (x,y) (vx, vy) = (x + (vx * time), y + (vy * time)) drawChar :: [String] -> ((Int,Int),(Int,Int)) -> [String] drawChar frame ((x,y),(vx,vy)) = if x < 0 || x >= sizeX || y < 0 || y >= sizeY then frame else (take mappedY frame) ++ [ (take mappedX row) ++ [ if char /= '' '' then ''x'' else if vy == 0 || abs (vx `div` vy) > 2 then ''-'' else if vx == 0 || abs (vy `div` vx) > 2 then ''|'' else if vx * vy >= 0 then ''/'' else ''//' ] ++ (drop (mappedX + 1) row) ] ++ (drop (mappedY + 1) frame) where reversedY = sizeY - y mappedX = x `div` 10 mappedY = reversedY `div` 10 row = frame !! mappedY char = row !! mappedX