Animação ASCII Ball in Box

11

Escreva um programa que exiba uma bola ASCII em movimento *dentro de um retângulo (20 por 10 caracteres, incluindo borda). A bola não deve cruzar o retângulo, por exemplo, esbarrar quando atingir a parede. A cena deve ser limpa e redesenhada a cada 0,1 segundos e a bola deve mover 1 caractere nas direções x e y a cada quadro. O programa mais curto escrito em qualquer idioma vence.

Exemplo de saída (quadro 1)

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

Exemplo de saída (quadro 2)

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

Exemplo de saída (quadro 8)

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

Exemplo de saída (quadro 9)

+------------------+
|                  |
|                  |
|                  |
|                  |
|                  |
|                  |
|        *         |
|                  |
+------------------+
Patrick Oscity
fonte
4
A impressão de 99 novas linhas se qualifica como limpar a tela?
Ventero
Não no meu monitor com 1080x1920resolução :)
mellamokb

Respostas:

7

Ruby 1.9, 115 caracteres

A lógica movimento é bastante semelhante ao Danko 's resposta .

Esta versão foi testada apenas no 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
fonte
Com o Ruby 1.9.3 no Windows 7, puts"\e[2J"apenas imprime ←[2J(e uma nova linha) na tela.
res
@res Veja minha edição para uma versão que deve ser executada no Windows (infelizmente não posso testá-la).
Ventero
Usar clsnão funciona para mim, mas system ("cls")funciona.
res
@res use `cls`. Backticks literais.
Mark Reed
@ MarkReed - Foi o que tentei escrever. Enfim, não funciona. O Windows parece exigir sistema ("cls").
res
4

Powershell, 144 caracteres

Com base na excelente resposta de Joey , usando o fato de que as coordenadas da bola são uma função do índice de quadros (i), portanto, se você tiver algo parecido x=n-abs(n-(i mod (2*n))), x passará de 0 para n, volta para 0 e assim por diante ...

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ć
fonte
Agradável. Embora eu estivesse meio orgulhoso do meu, if(-1,18-eq$x){$a*=-1;$x+=2*$a}if(-1,8-eq$y){$b*=-1;$y+=2*$b}que substituiu quatro ifsegundos antes ;-). Eu tinha certeza de que tinha que haver uma fórmula, no entanto.
Joey
3

Python 2, 234

Tenho certeza de que isso pode ser mais praticado, mas tenho que ir, então aqui está o que tenho. vai trabalhar mais nisso mais 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 no console de comandos do Windows. Outros sistemas operacionais podem usar um comando diferente do que clspara limpar a tela, comoclear

Blazer
fonte
faz print "\e[H\e[2J"o trabalho no windows?
Patrick Oscity
@padde - Parece que não funciona quando executo o seu programa Ruby no Windows 7 (veja meu comentário no seu post).
res
3

Ruby ( 179 174 147)

EDIT se livrou de mais alguns caracteres:

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 raspou alguns caracteres, agora 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}

Ungolfed:

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
fonte
Não deveria sleep .1funcionar também?
Joey
Não, não em 1.9. SyntaxError: (irb):1: no .<digit> floating literal anymore; put 0 before dot. Mas voltarei a isso se precisar no futuro, obrigado!
Patrick Oscity
Se você estiver em 1,9 você pode usar literais de char para encurtar algumas coisas, por exemplo, ?*em vez de '*', etc.
Joey
Usando o Ruby 1.9.3 no Win7, isso imprime retângulos um após (abaixo) o outro, cada um tendo ←[2J←[f+------------------+a primeira linha.
res
em seguida, mudar $> << "\e[2J\e[f"+fpara 'cls';$><<f(backticks de uso para cls)
Patrick Oscity
2

JavaScript ( 275283 )

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)

Demonstração: http://jsfiddle.net/eKcfu/2/

Eu escrevi isso rapidamente, então tenho certeza de que ainda há bastante espaço para melhorias. Sugestões são bem-vindas :)

Editar 1 : remover chamada de função separada desnecessária, incorporar diretamente setInterval.

mellamokb
fonte
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 uma abordagem mais funcional para calcular as coordenadas, criando a sequência infinita para cada coordenada separadamente e, em seguida, fechando-as juntas (linhas 2 e 3). O resto é desenhar código.

hammar
fonte
2

PowerShell, 184 185 215

Apenas semi-golfe, pois meu cérebro não está funcionando corretamente quando estou doente ...

Alguns truques legais, no entanto.

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]: Fazer um loop sobre o campo é muito mais curto.

Joey
fonte
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 graças ao DLosc

wastl
fonte
Agradável! Para o loop infinito, você pode usar DO ... LOOPno lugar de WHILE 1 ... WENDe salvar 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

Não inicia no canto superior esquerdo como o exemplo de saída, mas isso não é declarado como um requisito.

Kevin Reid
fonte
1

Ruby 1.9, 162 caracteres

35 caracteres a menos da resposta de @ Ventero, mas fiquei impressionado que consegui chegar até aqui ainda usando uma abordagem relativamente direta à lógica real. O ^ [é um ESC literal (1 caractere).

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
fonte
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
fonte
1

Outra entrada do bash - 213 204 caracteres

Não é realmente um vencedor, mas foi divertido. Ele usa sequências de caracteres vt100 para o desenho. (o código relatado aqui usa 215 caracteres para facilitar a leitura, dois caracteres podem ser removidos escapando, por exemplo, '*' -> \ *

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
fonte
1

Powershell, 139 bytes

Inspirado pela resposta 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 o -replaceoperador para desenhar *dentro do retângulo.

Script com menos golfe para explicar como 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
}
confuso
fonte
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

O \ e na linha echo -e "\e[$2;$1H$3"pode ser produzido por

echo -e "\x1b"

para substituí-lo. Como 0x1b binário, é 3 caracteres mais curto; Eu conto apenas 1 para "\ e", porque apenas o software de layout me obriga a usar \e.

Usuário desconhecido
fonte
Um usuário anônimo sugeriu edições para remover os $símbolos internos ((...))e substituí x=$(($x+$p))- los por ((x+=p))e similarmente na linha a seguir. (Eles também sugeriram o uso \edo caractere de escape).
Peter Taylor
Gostaria de sugerir, além disso, que \*pode funcionar como um substituto para "*".
Peter Taylor
@ PeterTaylor: Obrigado ao usuário anônimo. Incorporei a sugestão nº 1 e uso a nº 2 na forma modificada, e a sua.
usuário desconhecido
@userunknown: Você é representante do 1,337que precisa ser permanentemente bloqueado no local: P
mellamokb
1
@mellamokb: Acabou.
usuário desconhecido
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

Horrivelmente lento, mas funciona.

fase
fonte
(X=20)→Spode ser (X=20→S, e você pode tirar vantagem de Ans para economizar alguns bytes na final Por (circular Estou linhas positivas 8 e 9 podem ser golfed, mas eu não sei como no momento..
MI Wright
@MIWright Onde eu colocaria os Ans?
fase
"| \ Output(O,1,Ans \ Output(O,20,AnsDeveria trabalhar.
MI Wright
@MIWright Mas isso não substitui uma sequência de dois caracteres por uma de três caracteres? E adicionando a cadeia de dois caracteres acima, tornando-a +4?
fase
O que você quer dizer? Ansé um token de um byte , digitado com 2nd (-). Isso acabará economizando um byte, pois o |token tem dois bytes na calculadora.
MI Wright
0

PHP, 196186181 bytes

Eu removi evitando um estouro inteiro para salvar 6 bytes. Será executado por 29 bilhões de anos antes do estouro; ainda 6,8 anos em um sistema de 32 bits. Eu diria que é aceitável.

Calcular a posição em vez de ajustá-la economizou muito, preparando o modelo completo de uma só vez.

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;

Corra com -nr. Requer PHP 7.1.

repartição :

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
fonte