ASCII Ball in Box Animation

11

Tulis program yang menampilkan bola ASCII bergerak *di dalam persegi panjang (20 dengan 10 karakter termasuk perbatasan). Bola tidak boleh melewati kotak, misalnya menabrak ketika menyentuh dinding. Adegan harus dibersihkan dan digambar ulang setiap 0,1 detik dan bola harus menggerakkan 1 karakter dalam arah x dan y setiap frame. Program terpendek yang ditulis dalam bahasa apa pun menang.

Contoh output (frame 1)

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

Contoh output (bingkai 2)

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

Contoh output (frame 8)

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

Contoh output (frame 9)

+------------------+
|                  |
|                  |
|                  |
|                  |
|                  |
|                  |
|        *         |
|                  |
+------------------+
Patrick Oscity
sumber
4
Apakah mencetak 99 baris baru memenuhi syarat sebagai membersihkan layar?
Ventero
Tidak pada monitor saya dengan 1080x1920resolusi :)
mellamokb

Jawaban:

7

Ruby 1.9, 115 karakter

Logika Gerakan ini sangat mirip dengan Danko 's jawaban .

Versi ini telah diuji di Linux saja.

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
sumber
Dengan Ruby 1.9.3 di bawah Windows 7, puts"\e[2J"cukup cetak ←[2J(dan baris baru) di layar.
res
@res Lihat hasil edit saya untuk versi yang seharusnya berjalan pada Windows (sayangnya tidak dapat mengujinya sendiri).
Ventero
Menggunakan clstidak bekerja untuk saya, tetapi system ("cls")tidak.
res
@res gunakan `cls`. Backticks literal.
Mark Reed
@ MarkReed - Itulah yang saya coba tulis .. Lagipula, tidak berhasil. Windows tampaknya membutuhkan sistem ("cls").
res
4

Powershell, 144 karakter

Berdasarkan jawaban Joey yang luar biasa , menggunakan fakta bahwa koordinat bola adalah fungsi dari frame index (i), jadi jika Anda memiliki sesuatu seperti x=n-abs(n-(i mod (2*n))), x akan berubah dari 0 ke n, kembali ke 0, dan seterusnya ...

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ć
sumber
Bagus Meskipun saya agak bangga dengan saya if(-1,18-eq$x){$a*=-1;$x+=2*$a}if(-1,8-eq$y){$b*=-1;$y+=2*$b}yang menggantikan empat ifs sebelumnya ;-). Tapi saya yakin harus ada formula.
Joey
3

Python 2, 234

Saya yakin ini bisa bermain golf lebih banyak, tetapi saya harus pergi jadi inilah yang saya miliki. akan bekerja lebih banyak lagi nanti

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)

Catatan: berfungsi pada konsol perintah Windows. Sistem operasi lain mungkin menggunakan perintah yang berbeda dari clsuntuk membersihkan layar, seperticlear

Jaket
sumber
tidak print "\e[H\e[2J"berfungsi di windows?
Patrick Oscity
@padde - Sepertinya tidak berfungsi ketika saya menjalankan program Ruby Anda di Windows 7 (lihat komentar saya untuk posting Anda).
res
3

Ruby ( 179 174 147)

EDIT menghilangkan beberapa karakter lagi:

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 mencukur beberapa karakter, sekarang 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}

Tidak Disatukan:

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
sumber
Tidak seharusnya sleep .1bekerja juga?
Joey
Tidak, tidak di 1.9. SyntaxError: (irb):1: no .<digit> floating literal anymore; put 0 before dot. Tapi saya akan kembali ke itu jika saya membutuhkannya di masa depan, terima kasih!
Patrick Oscity
Jika Anda menggunakan 1,9, Anda dapat menggunakan char literals untuk mempersingkat beberapa hal, misalnya ?*alih-alih '*', dll.
Joey
Menggunakan Ruby 1.9.3 di bawah Win7, ini mencetak persegi panjang satu setelah (di bawah) yang lain, masing-masing memiliki ←[2J←[f+------------------+sebagai baris pertama.
res
lalu ubah $> << "\e[2J\e[f"+fke 'cls';$><<f(gunakan backticks untuk 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)

Demo: http://jsfiddle.net/eKcfu/2/

Saya menulis ini dengan cukup cepat jadi saya yakin masih ada sedikit ruang untuk perbaikan. Saran dipersilahkan :)

Sunting 1 : Hapus panggilan fungsi terpisah yang tidak perlu, sematkan langsung di setInterval.

mellamokb
sumber
2

Haskell, 212 karakter

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

Gunakan pendekatan yang lebih fungsional untuk menghitung koordinat, dengan membuat urutan tak terbatas untuk masing-masing koordinat secara terpisah dan kemudian mengikatnya bersama-sama (baris 2 dan 3). Sisanya menggambar kode.

hammar
sumber
2

PowerShell, 184 185 215

Hanya semi-golf karena otak saya tidak berfungsi dengan baik ketika saya sakit ...

Tapi ada beberapa trik bagus di dalamnya.

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}

[Sunting]: Looping di atas lapangan jauh lebih pendek.

Joey
sumber
2

QBasic (QB64), 178 173 byte

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 byte berkat DLosc

wastl
sumber
Bagus! Untuk loop tak terbatas, Anda dapat menggunakan DO ... LOOPdi tempat WHILE 1 ... WENDdan menyimpan 5 byte.
DLosc
1

Perl 5, 141 karakter

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

Tidak mulai di sudut kiri atas seperti contoh output, tetapi itu tidak dinyatakan sebagai persyaratan.

Kevin Reid
sumber
1

Ruby 1.9, 162 karakter

35 karakter malu dengan jawaban @ Ventero, tapi saya terkesan bahwa saya bisa turun sejauh ini sambil masih menggunakan pendekatan yang relatif mudah ke logika yang sebenarnya. ^ [Adalah ESC literal (1 char).

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

R, 233 karakter

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

Entri bash lain - 213 204 karakter

Sebenarnya bukan pemenang hadiah, tapi tetap saja menyenangkan. Ini menggunakan urutan char vt100 untuk gambar. (kode yang dilaporkan di sini menggunakan 215 karakter untuk dibaca, 2 karakter dapat dihapus dengan melarikan diri, misalnya '*' -> \ *

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

Powershell, 139 byte

Terinspirasi oleh jawaban 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}

Script ini menggunakan -replaceoperator untuk menggambar *di dalam persegi panjang.

Lebih sedikit skrip golf untuk menjelaskan cara kerjanya:

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
sumber
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

\ E di baris echo -e "\e[$2;$1H$3"dapat diproduksi oleh

echo -e "\x1b"

untuk menggantinya. Sebagai biner 0x1b, 3 karakter lebih pendek; Saya menghitung hanya 1 untuk "\ e", karena hanya perangkat lunak tata letak yang memaksa saya untuk menggunakannya \e.

Pengguna tidak diketahui
sumber
Seorang pengguna anonim menyarankan suntingan untuk menghapus $simbol di dalamnya ((...))dan mengganti x=$(($x+$p))dengan ((x+=p))dan juga pada baris berikut. (Mereka juga menyarankan penggunaan \euntuk karakter pelarian).
Peter Taylor
Saya akan menyarankan sebagai tambahan yang \*mungkin berfungsi sebagai pengganti "*".
Peter Taylor
@PeterTaylor: Terima kasih kepada pengguna anonim. Saya memasukkan saran no 1, dan menggunakan no 2 dalam bentuk yang dimodifikasi, dan saran Anda.
pengguna tidak diketahui
@userunknown: Anda 1,337perlu dikunci secara permanen di tempat: P
mellamokb
1
@ellamokb: Sudah pergi.
pengguna tidak diketahui
0

TI Basic, 169 167 byte

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

Sangat lambat, tapi berhasil.

tahap
sumber
(X=20)→Sdapat (X=20→S, dan Anda dapat mengambil keuntungan dari Ans untuk menyimpan beberapa byte di akhir For (loop. Saya positif baris 8 dan 9 dapat golf, tapi saya tidak yakin bagaimana saat ini.
MI Wright
@ IMWright Di mana saya akan meletakkan Ans?
fase
"| \ Output(O,1,Ans \ Output(O,20,Ansharus bekerja.
MI Wright
@ IMWright Tapi bukankah itu menggantikan string dua karakter dengan string tiga karakter? Dan menambahkan dua karakter string di atasnya, menjadikannya +4?
fase
Maksud kamu apa? Ansadalah token satu byte , diketik dengan 2nd (-). Itu akhirnya akan menghemat satu byte, karena |tokennya dua byte pada kalkulator.
MI Wright
0

PHP, 196 186 148 byte

Saya menghapus menghindari integer overflow untuk menghemat 6 byte. Itu akan berjalan selama 29 miliar tahun sebelum meluap; masih 6,8 tahun pada sistem 32 bit. Saya katakan itu bisa diterima.

Menghitung posisi alih-alih menyesuaikannya banyak menghemat, menyiapkan templat lengkap sekaligus lot lain.

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;

Jalankan dengan -nr. Membutuhkan PHP 7.1.

kerusakan :

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
sumber