Animation ASCII Ball in Box

11

Écrivez un programme qui affiche une boule ASCII en mouvement à l' *intérieur d'un rectangle (20 x 10 caractères, y compris la bordure). La balle ne doit pas traverser le rectangle, par exemple se heurter lorsqu'elle heurte le mur. La scène doit être nettoyée et redessinée toutes les 0,1 secondes et la balle doit se déplacer de 1 caractère dans les directions x et y à chaque image. Le programme le plus court écrit dans n'importe quelle langue gagne.

Exemple de sortie (image 1)

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

Exemple de sortie (image 2)

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

Exemple de sortie (image 8)

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

Exemple de sortie (image 9)

+------------------+
|                  |
|                  |
|                  |
|                  |
|                  |
|                  |
|        *         |
|                  |
+------------------+
Patrick Oscity
la source
4
L'impression de 99 sauts de ligne est-elle considérée comme un effacement de l'écran?
Ventero
Pas sur mon moniteur avec une 1080x1920résolution :)
mellamokb

Réponses:

7

Ruby 1.9, 115 caractères

La logique du mouvement est assez similaire à la réponse de Danko .

Cette version a été testée uniquement sur 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
la source
Avec Ruby 1.9.3 sous Windows 7, il puts"\e[2J"suffit d'imprimer ←[2J(et une nouvelle ligne) à l'écran.
res
@res Voir mon édition pour une version qui devrait fonctionner sur Windows (je ne peux malheureusement pas la tester moi-même).
Ventero
L'utilisation clsne fonctionne pas pour moi, mais le system ("cls")fait.
res
@res utilise `cls`. Astuces littérales.
Mark Reed
@MarkReed - C'est ce que j'ai essayé d'écrire. Quoi qu'il en soit, cela ne fonctionne pas. Windows semble nécessiter un système ("cls").
res
4

Powershell, 144 caractères

Sur la base de l' excellente réponse de Joey , en utilisant le fait que les coordonnées de la balle sont fonction de l'indice de trame (i), donc si vous avez quelque chose comme x=n-abs(n-(i mod (2*n))), x passera de 0 à n, reviendra à 0, et ainsi de suite ...

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ć
la source
Joli. Bien que j'étais un peu fier de mon if(-1,18-eq$x){$a*=-1;$x+=2*$a}if(-1,8-eq$y){$b*=-1;$y+=2*$b}qui a remplacé quatre ifs plus tôt ;-). Mais j'étais sûr qu'il devait y avoir une formule.
Joey
3

Python 2, 234

Je suis sûr que cela peut être joué davantage, mais je dois y aller, alors voici ce que j'ai. travaillera plus sur elle plus tard

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)

remarque: fonctionne sur la console de commande Windows. D'autres systèmes d'exploitation peuvent utiliser une commande différente de celle clspour effacer l'écran, commeclear

blazer
la source
fait le print "\e[H\e[2J"travail sur les fenêtres?
Patrick Oscity du
@padde - Cela ne semble pas fonctionner lorsque j'exécute votre programme Ruby sous Windows 7 (voir mon commentaire sur votre article).
res
3

Ruby ( 179 174 147)

EDIT s'est débarrassé de quelques autres caractères:

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 a supprimé certains caractères, maintenant 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}

Non 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
la source
Ça ne devrait pas sleep .1marcher aussi?
Joey
Non, pas en 1.9. SyntaxError: (irb):1: no .<digit> floating literal anymore; put 0 before dot. Mais j'y reviendrai si j'en ai besoin à l'avenir, merci!
Patrick Oscity
Si vous êtes sur 1.9, vous pouvez utiliser des littéraux de caractères pour raccourcir certaines choses, par exemple ?* au lieu de '*', etc.
Joey
En utilisant Ruby 1.9.3 sous Win7, cela imprime des rectangles les uns après les autres, chacun ayant ←[2J←[f+------------------+comme première ligne.
res
puis changez $> << "\e[2J\e[f"+f en 'cls';$><<f(utilisez des astuces pour 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)

Démo: http://jsfiddle.net/eKcfu/2/

J'ai écrit cela assez rapidement, donc je suis sûr qu'il y a encore beaucoup de place pour l'amélioration. Les suggestions sont les bienvenues :)

Édition 1 : supprimez les appels de fonction séparés inutiles, intégrez-les directement setInterval.

mellamokb
la source
2

Haskell, 212 caractères

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

Utilise une approche plus fonctionnelle pour calculer les coordonnées, en faisant la séquence infinie pour chaque coordonnée séparément puis en les zippant ensemble (lignes 2 et 3). Le reste est le code de dessin.

hammar
la source
2

PowerShell, 184 185 215

Seulement semi-golfé car mon cerveau ne fonctionne pas correctement quand je suis malade ...

Quelques belles astuces, cependant.

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}

[Modifier]: La boucle sur le champ est beaucoup plus courte.

Joey
la source
2

QBasic (QB64), 178 173 octets

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 octets grâce à DLosc

wastl
la source
Agréable! Pour la boucle infinie, vous pouvez utiliser DO ... LOOPà la place WHILE 1 ... WENDet enregistrer 5 octets.
DLosc
1

Perl 5, 141 caractères

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

Ne démarre pas dans le coin supérieur gauche comme le fait l'exemple de sortie, mais cela n'est pas indiqué comme une exigence.

Kevin Reid
la source
1

Ruby 1.9, 162 caractères

35 caractères timides de la réponse de @ Ventero, mais j'ai été impressionné de pouvoir le faire aussi loin tout en utilisant une approche relativement simple de la logique réelle. Le ^ [est un ESC littéral (1 caractère).

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
la source
1

R, 233 caractères

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
la source
1

Une autre entrée bash - 213 204 caractères

Pas vraiment un lauréat, mais c'était quand même amusant. Il utilise des séquences de caractères vt100 pour le dessin. (le code rapporté ici utilise 215 caractères pour la lisibilité, 2 caractères peuvent être supprimés en s'échappant, par exemple '*' -> \ *

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
la source
1

Powershell, 139 octets

Inspiré par la réponse 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}

Ce script utilise l' -replaceopérateur pour dessiner *à l'intérieur du rectangle.

Script moins golfé pour expliquer comment cela fonctionne:

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
la source
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

Le \ e dans la ligne echo -e "\e[$2;$1H$3" peut être produit par

echo -e "\x1b"

pour le remplacer. En tant que binaire 0x1b, il est plus court de 3 caractères; Je compte seulement 1 pour "\ e", car seul le logiciel de mise en page me force à utiliser \e.

Utilisateur inconnu
la source
Un utilisateur anonyme a suggéré des modifications pour supprimer les $symboles à l'intérieur ((...))et les remplacer x=$(($x+$p))par ((x+=p))et de la même manière sur la ligne suivante. (Ils ont également suggéré d'utiliser \ele caractère d'échappement).
Peter Taylor
Je suggère en outre que cela \*pourrait fonctionner en remplacement de "*".
Peter Taylor
@PeterTaylor: Merci à l'utilisateur anonyme. J'ai incorporé la suggestion n ° 1 et j'utilise la n ° 2 sous forme modifiée, et la vôtre.
utilisateur inconnu
@userunknown: Votre représentant a 1,337besoin d'être verrouillé en place de façon permanente: P
mellamokb
1
@mellamokb: C'est parti.
utilisateur inconnu
0

TI Basic, 169 167 octets

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

Horriblement lent, mais ça marche.

phase
la source
(X=20)→Speut être (X=20→S, et vous pouvez profiter d'Ans pour économiser quelques octets dans la boucle finale de For (je suis positif, les lignes 8 et 9 peuvent être jouées, mais je ne sais pas comment pour le moment.
MI Wright
@MIWright Où mettrais-je les Ans?
phase
"| \ Output(O,1,Ans \ Output(O,20,Ansdevrait marcher.
MI Wright
@MIWright Mais n'est-ce pas remplacer une chaîne de deux caractères par une chaîne de trois caractères? Et en ajoutant la chaîne de deux caractères au-dessus, ce qui en fait +4?
phase
Que voulez-vous dire? Ansest un jeton d'un octet , tapé avec 2nd (-). Cela finira par économiser un octet, car le |jeton est de deux octets sur la calculatrice.
MI Wright
0

PHP, 196 186 octets

J'ai supprimé en évitant un débordement d'entier pour économiser 6 octets. Il durera 29 milliards d'années avant de déborder; encore 6,8 ans sur un système 32 bits. Je dirais que c'est acceptable.

Le calcul de la position au lieu de l'ajuster a sauvé beaucoup de choses, en préparant le modèle complet à la fois un autre lot.

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;

Courez avec -nr. Nécessite PHP 7.1.

panne :

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
la source