Animación ASCII Ball in Box

11

Escriba un programa que muestre una bola ASCII en movimiento *dentro de un rectángulo (20 por 10 caracteres, incluido el borde). La pelota no debe cruzar el rectángulo, por ejemplo, golpearse cuando golpea la pared. La escena se debe borrar y volver a dibujar cada 0.1 segundos y la bola debe moverse 1 char en dirección x e y cada cuadro. El programa más corto escrito en cualquier idioma gana.

Ejemplo de salida (cuadro 1)

+------------------+
|*                 |
|                  |
|                  |
|                  |
|                  |
|                  |
|                  |
|                  |
+------------------+

Ejemplo de salida (marco 2)

+------------------+
|                  |
| *                |
|                  |
|                  |
|                  |
|                  |
|                  |
|                  |
+------------------+

Ejemplo de salida (cuadro 8)

+------------------+
|                  |
|                  |
|                  |
|                  |
|                  |
|                  |
|                  |
|       *          |
+------------------+

Ejemplo de salida (cuadro 9)

+------------------+
|                  |
|                  |
|                  |
|                  |
|                  |
|                  |
|        *         |
|                  |
+------------------+
Patrick Oscity
fuente
44
¿La impresión de 99 líneas nuevas califica como borrar la pantalla?
Ventero
No en mi monitor con 1080x1920resolución :)
mellamokb

Respuestas:

7

Ruby 1.9, 115 caracteres

La lógica del movimiento es bastante similar a la respuesta de Danko .

Esta versión ha sido probada solo en Linux.

p=0
loop{u=(?|+?\s*18+"|
")*8
u[165-21*(7-p%14).abs-(17-p%34).abs]=?*
p+=1
puts"\e[2J",r=?++?-*18+?+,u,r
sleep 0.1}
Ventero
fuente
Con Ruby 1.9.3 en Windows 7, puts"\e[2J"solo imprime ←[2J(y una nueva línea) en la pantalla.
res
@res Vea mi edición para ver una versión que debería ejecutarse en Windows (desafortunadamente no puedo probarla).
Ventero
Usar clsno funciona para mí, pero system ("cls")sí.
res
@res usa `cls`. Backticks literales.
Mark Reed
@ MarkReed - Eso es lo que intenté escribir ... De todos modos, no funciona. Windows parece requerir sistema ("cls").
res
4

Powershell, 144 caracteres

Basado en la excelente respuesta de Joey , usando el hecho de que las coordenadas de la bola son una función del índice de cuadro (i), por lo que si tiene algo como x=n-abs(n-(i mod (2*n))), x irá de 0 a n, volverá a 0, y así sucesivamente ...

for(){cls
($l="+$('-'*18)+")
7..0|%{$j=$_
"|$(-join(17..0|%{'* '[$j-[Math]::abs(7-$i%14)-or$_-[Math]::abs(17-$i%34)]}))|"}
$l;$i++;sleep -m 100}
Danko Durbić
fuente
Buena esa. Aunque estaba un poco orgulloso de mi, if(-1,18-eq$x){$a*=-1;$x+=2*$a}if(-1,8-eq$y){$b*=-1;$y+=2*$b}que reemplazó cuatro ifs antes ;-). Sin embargo, estaba seguro de que tenía que haber una fórmula.
Joey
3

Pitón 2, 234

Estoy seguro de que esto se puede jugar más, pero tengo que irme, así que esto es lo que tengo sofar. trabajará más en eso más tarde

import os,time
a,b,c,d,e,n='+- |*\n'
w=d+c*18+d+n
s=a+b*18+a+n
x,y=0,0
g,h=17,7
j,k=1,1
while 1:
 if 0>x or x>g:j*=-1;x+=j
 if 0>y or y>h:k*=-1;y+=k
 os.system('cls');print s+w*y+d+c*x+e+c*(g-x)+d+n+w*(h-y)+s;x+=j;y+=k;time.sleep(0.1)

nota: funciona en la consola de comandos de Windows. Otros sistemas operativos pueden usar un comando diferente clsal de borrar la pantalla, comoclear

Chaqueta de sport
fuente
hace print "\e[H\e[2J"funcionar en Windows?
Patrick Oscity el
@padde: no parece funcionar cuando ejecuto su programa Ruby en Windows 7 (vea mi comentario en su publicación).
res
3

Rubí ( 179 174 147)

EDIT eliminó algunos caracteres más:

l=?++?-*18+?++?\n
c=?|+?\s*18+?|+?\n
p=22
u=v=1
loop{f=l+c*8+l
f[p]=?*
puts"\e[2J"+f
p+=(u=f[p+u]==' '?u:-u)+21*(v=f[p+21*v]==' '?v:-v)
sleep 0.1}

EDIT afeitado algunos caracteres, ahora 174:

l="+#{'-'*18}+\n";f=l+"|#{' '*18}|\n"*8+l;x=y=u=v=1
loop{f[21*y+x]='*';$><<"\e[2J\e[f"+f;f[21*y+x]=' '
u=f[21*y+x+u]==' '?u:-u;v=f[21*(y+v)+x]==' '?v:-v
x+=u;y+=v;sleep 0.1}

Sin golf:

l="+#{'-'*18}+\n"           # top and bottom lines 
f=l+"|#{' '*18}|\n"*8+l     # complete box as string
x=y=u=v=1                   # x,y position; u,v next move
loop {                      #
  f[21*y+x]='*'             # add ball to box
  $> << "\e[2J\e[f"+f       # clear screen and print box with ball
  f[21*y+x]=' '             # remove ball from box
  u=f[21*y+x+u]==' '?u:-u   # next move in x direction
  v=f[21*(y+v)+x]==' '?v:-v # next move in y direction
  x+=u                      # perform move
  y+=v                      # --"--
  sleep 0.1                 # .zZZ...
}                           #
Patrick Oscity
fuente
¿No debería sleep .1funcionar también?
Joey
No, no en 1.9. SyntaxError: (irb):1: no .<digit> floating literal anymore; put 0 before dot. Pero volveré a eso si lo necesito en el futuro, ¡gracias!
Patrick Oscity
Si estás en 1.9 puedes usar literales char para acortar algunas cosas, por ejemplo, en ?*lugar de '*', etc.
Joey
Usando Ruby 1.9.3 bajo Win7, esto imprime rectángulos uno después (debajo) del otro, cada uno con ←[2J←[f+------------------+la primera línea.
res
luego cambie $> << "\e[2J\e[f"+fa 'cls';$><<f(use backticks para cls)
Patrick Oscity
2

JavaScript (275 283 )

s=Array(19).join(' ');n='\n';z=Array(9).join('|'+s+'|'+n).split(n,8);
x=y=0;a=b=1;t='+'+s.replace(/ /g,'-')+'+';
setInterval(function(){u=z[y];z[y]=u.replace(eval('/( {'+x+'}) /'),'$1*');
$('#o').text(t+n+z.join('\n')+n+t);z[y]=u;x+=a;y+=b;if(!x|x==17)a=-a;if(!y|y==7)b=-b},100)

Demostración: http://jsfiddle.net/eKcfu/2/

Escribí esto bastante rápido, así que estoy seguro de que todavía hay bastante margen de mejora. Las sugerencias son bienvenidas :)

Edición 1 : elimine la llamada de función separada innecesaria, incrustar directamente en setInterval.

mellamokb
fuente
2

Haskell, 212 caracteres

import System
main=mapM_ f$s 19`zip`s 9
s n=[2..n]++[n-1,n-2..3]++s n
f p=r"clear">>putStr(unlines[[" |-+*"!!(19#i+2*(9#j)+4*e((i,j)==p))|i<-[1..20]]|j<-[1..10]])>>r"sleep 0.1"
b#n=e$n<2||n>b
e=fromEnum
r=system

Utiliza un enfoque más funcional para calcular las coordenadas, haciendo la secuencia infinita para cada coordenada por separado y luego comprimiéndolas (líneas 2 y 3). El resto es código de dibujo.

hammar
fuente
2

PowerShell, 184 185 215

Solo semi-golf ya que mi cerebro no funciona correctamente cuando estoy enfermo ...

Sin embargo, hay algunos buenos trucos.

for($a=$b=1){cls
($l="+$('-'*18)+")
0..7|%{$j=$_
"|$(-join(0..17|%{'* '[$j-$y-or$_-$x]}))|"}
$l
$x+=$a;$y+=$b
if(-1,18-eq$x){$a*=-1;$x+=2*$a}if(-1,8-eq$y){$b*=-1;$y+=2*$b}sleep -m 100}

[Editar]: recorrer el campo es mucho más corto.

Joey
fuente
2

QBasic (QB64), 178 173 bytes

a$="+------------------+
?a$
for c=1to 8
?"|                  |
next
?a$
do
x=19-abs(17-(i mod 34))
y=9-abs(7-(i mod 14))
locate y,x
?"*
_delay .1
locate y,x
?" "
i=i+1
loop

-5 bytes gracias a DLosc

wastl
fuente
¡Agradable! Para el bucle infinito, puede usar DO ... LOOPen lugar de WHILE 1 ... WENDy guardar 5 bytes.
DLosc
1

Perl 5, 141 caracteres

print"\e[H\e[2J",$h="+"."-"x18 ."+
",(map{"|".$"x$q,(abs$t%14-7)-$_?$":"*",$"x(17-$q),"|
"}0..7),$h,select'','','',0.1while$q=abs$t++%34-17,1

No comienza en la esquina superior izquierda como lo hace la salida de ejemplo, pero eso no se establece como un requisito.

Kevin Reid
fuente
1

Ruby 1.9, 162 caracteres

35 caracteres menos que la respuesta de @Ventero, pero me impresionó poder llegar hasta aquí sin dejar de utilizar un enfoque relativamente sencillo de la lógica real. El ^ [es un ESC literal (1 carácter).

x=y=0
v=h=1
s=' '
loop{puts"^[[2J"+b="+#{?-*18}+",*(0..7).map{|i|"|#{i!=y ?s*18:s*x+?*+s*(17-x)}|"},b
y+=v
y+=v*=-1if y<0||y>7
x+=h
x+=h*=-1if x<0||x>17
sleep 0.1}
Mark Reed
fuente
1

R, 233 caracteres

s=c("\n+",rep("-",18),"+");for (j in 1:8){cat(s,sep="");cat(rep(c("\n|",rep("",17),"|"),j-1));cat(c("\n|",rep(" ",j-1),"*",rep(" ",18-j),"|"),sep="");cat(rep(c("\n|",rep("",17),"|"),8-j));cat(s,sep="");Sys.sleep(0.1);system("clear")}
Paolo
fuente
1

Otra entrada de bash: 213 204 caracteres

No es realmente un ganador del premio, pero de todos modos fue divertido. Utiliza secuencias de caracteres vt100 para el dibujo. (el código reportado aquí usa 215 caracteres para facilitar la lectura, se pueden eliminar 2 caracteres escapando, por ejemplo, '*' -> \ *

e(){ printf "\e[$1";}
e 2J;e H
h='+------------------+'
echo $h
for((;++j<9;));do printf '|%18s|\n';done
echo $h
e '3;2H*'
while :;do
e 'D '
((i/17%2))&&e D||e C
((++i/7%2))&&e A||e B
e 'D*'
sleep .1
done
Dan Andreatta
fuente
1

Powershell, 139 bytes

Inspirado por la respuesta de Danko Durbić .

for(){cls
,"+$('-'*18)+
"*2-join("|$(' '*18)|
"*8-replace"^(\W{$(21*[Math]::abs(7-$i%14)+[Math]::abs(17-$i++%34))}.) ",'$1*')
sleep -m 100}

Este script usa el -replaceoperador para dibujar *dentro del rectángulo.

Menos guión de golf para explicar cómo funciona:

for(){
    cls
    $y=[Math]::abs(7-$i%14)
    $x=[Math]::abs(17-$i++%34)
    $b="+$('-'*18)+`n"
    $m="|$(' '*18)|`n"*8-replace"^(\W{$(21*$y+$x)}.) ",'$1*'
    ,$b*2-join($m)          # draw it
    sleep -m 100
}
mazzy
fuente
0

Bash 278 300, 296

h="+------------------+"
w="|                  |"
g(){
echo -e "\e[$2;$1H$3"
}
g 1 1 $h
for i in {1..8}
do
echo "$w"
done
echo $h
x=4
y=4
p=1
q=1
for((;;))
do
((x==19&&p==1||x==2&&p==-1))&&p=-$p
((y==9&&q==1||y==2&&q==-1))&&q=-$q
x=$((x+p))
y=$((y+q))
g $x $y \*
sleep .1
g $x $y " "
done

El \ e en la línea echo -e "\e[$2;$1H$3"puede ser producido por

echo -e "\x1b"

para reemplazarlo Como binario 0x1b es 3 caracteres más corto; Cuento solo 1 para "\ e", porque solo el software de diseño me obliga a usar \e.

usuario desconocido
fuente
Un usuario anónimo ediciones sugerido para eliminar los $símbolos en el interior ((...))y reemplazan x=$(($x+$p))con ((x+=p))y de manera similar en la línea siguiente. (También sugirieron usar \epara el personaje de escape).
Peter Taylor
Sugeriría además que \*podría funcionar como un reemplazo para "*".
Peter Taylor
@PeterTaylor: Gracias al usuario anónimo. Incorporé la sugerencia no 1, y uso no 2 en forma modificada, y la suya.
usuario desconocido el
@userunknown: Su representante de 1,337necesidades debe estar permanentemente bloqueado en su lugar: P
mellamokb
1
@mellamokb: Se fue.
usuario desconocido el
0

TI Basic, 169 167 bytes

1→X
1→Y
1→S
1→T
While 1
ClrHome
Output(Y,X,"*
S(X>1 and X<20)+(X=1)-(X=20→S
T(Y>1 and Y<10)+(Y=1)-(Y=10→T
X+S→X
Y+T→Y
For(N,1,20,19
For(O,1,10,9
Output(O,N,"+
End
End
For(N,2,19
For(O,1,10,9
Output(O,N,"-
End
End
For(O,2,9
Output(O,1,"|
Output(O,20,"|
End
End

Horriblemente lento, pero funciona.

fase
fuente
(X=20)→Spuede ser (X=20→S, y puede aprovechar Ans para guardar algunos bytes en el For final (bucle. Estoy seguro de que las líneas 8 y 9 se pueden jugar, pero no estoy seguro de cómo hacerlo en este momento.
MI Wright
@MIWright ¿Dónde pondría el Ans?
Fase
"| \ Output(O,1,Ans \ Output(O,20,AnsDeberia trabajar.
MI Wright
@MIWright Pero, ¿no es eso reemplazar una cadena de dos caracteres con una cadena de tres caracteres? ¿Y agregando la cadena de dos caracteres por encima, haciendo que sea +4?
fase
¿Qué quieres decir? Anses un token de un byte , escrito con 2nd (-). Eso terminará ahorrando un byte, ya que el |token tiene dos bytes en la calculadora.
MI Wright
0

PHP, 196186148 bytes

Eliminé evitando un desbordamiento de enteros para guardar 6 bytes. Se ejecutará durante 29 mil millones de años antes del desbordamiento; Todavía 6.8 años en un sistema de 32 bits. Yo diría que eso es aceptable.

Calcular la posición en lugar de ajustarla ahorró mucho, preparando la plantilla completa en otro lote.

for(;++$i;$s[-3-21*abs($i%14-7)-abs($i%34-17)]="*",print$f(_,9e5,"
").$s.$z,usleep(1e5))$s=($f=str_pad)($z=$f("+",19,"-")."+
",189,$f("|",19)."|
");
").$z;

Corre con -nr. Requiere PHP 7.1.

desglose :

for(;++$i;      # infinite loop:
                    # 2. set asterisk at appropriate position
    $s[-3-21*abs($i%14-7)-abs($i%34-17)]="*";
                    # 3. clear screen: print 900k newlines
    print$f(_,9e5*0+2,"\n")
            .$s.$z, # 4. print field
    usleep(1e5))    # 5. sleep 100000 microseconds
                    # 1. create template
    $s=($f=str_pad)($z=$f("+",19,"-")."+\n",189,$f("|",19)."|\n");
Titus
fuente