Tell me more ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Write a program that displays a moving ASCII ball * inside a rectangle (20 by 10 chars including border). The ball must not cross the rectangle, e.g. bump off when it hits the wall. The scene must be cleared and redrawn every 0.1 seconds and the ball must move 1 char in x and y direction every frame. The shortest program written in any language wins.

Example output (frame 1)

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

Example output (frame 2)

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

Example output (frame 8)

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

Example output (frame 9)

+------------------+
|                  |
|                  |
|                  |
|                  |
|                  |
|                  |
|        *         |
|                  |
+------------------+
share|improve this question
2  
Does printing 99 newlines qualify as clearing the screen? – Ventero Apr 27 '12 at 13:52
Not on my monitor with 1080x1920 resolution :) – mellamokb Apr 27 '12 at 14:10

12 Answers

up vote 6 down vote accepted

Ruby 1.9, 115 characters

The movement logic is quite similar to Danko's answer.

This version has been tested on Linux only.

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}
share|improve this answer
With Ruby 1.9.3 under Windows 7, puts"\e[2J" just prints ←[2J (and a newline) on the screen. – r.e.s. Apr 27 '12 at 1:55
@r.e.s. See my edit for a version which should run on Windows (can't test it myself unfortunately). – Ventero Apr 27 '12 at 2:06
Using cls doesn't work for me, but system ("cls") does. – r.e.s. Apr 27 '12 at 4:14
@r.e.s. use `cls`. Literal backticks. – Mark Reed Apr 27 '12 at 4:34
@MarkReed - That's what I tried to write .. Anyway, it doesn't work. Windows seems to require system("cls"). – r.e.s. Apr 27 '12 at 5:43
show 8 more comments

Python 2, 234

I'm sure this can be golfed more, but I gotta go so here's what I have sofar. will work more on it later

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)

note: works on Windows command console. Other operating systems may use a different command than cls to clear the screen, such as clear

share|improve this answer
does print "\e[H\e[2J" work on windows? – padde Apr 26 '12 at 21:00
@padde - It doesn't seem to work when I run your Ruby program under Windows 7 (see my comment to your post). – r.e.s. Apr 27 '12 at 1:41

Powershell, 144 characters

Based on Joey's excellent answer, using the fact that the ball coordinates are a function of the frame index (i), so if you have something like x=n-abs(n-(i mod (2*n))), x will go from 0 to n, back to 0, and so on...

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}
share|improve this answer
Nice one. Although I was kinda proud of my if(-1,18-eq$x){$a*=-1;$x+=2*$a}if(-1,8-eq$y){$b*=-1;$y+=2*$b} which replaced four ifs earlier ;-). I was sure there had to be a formula, though. – Joey Apr 27 '12 at 5:14

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/

I wrote this up pretty quickly so I'm sure there's still quite a bit of room for improvement. Suggestions are welcome :)

Edit 1: Remove unnecessary separate function call, embed directly in setInterval.

share|improve this answer

Haskell, 212 characters

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

Uses a more functional approach for calculating the coordinates, by making the infinite sequence for each coordinate separately and then zipping them together (lines 2 and 3). The rest is drawing code.

share|improve this answer

PowerShell, 184 185 215

Only semi-golfed as my brain isn't working properly when I'm sick ...

A few nice tricks in it, though.

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}

[Edit]: Looping over the field is much shorter.

share|improve this answer

Ruby (179 174 147)

EDIT got rid of some more chars:

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 shaved off some chars, now 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...
}                           #
share|improve this answer
Shouldn't sleep .1 work too? – Joey Apr 26 '12 at 20:44
Nope, not in 1.9. SyntaxError: (irb):1: no .<digit> floating literal anymore; put 0 before dot. But i'll get back to that if i need it in the future, thanks! – padde Apr 26 '12 at 20:47
If you're on 1.9 you can use char literals to shorten a few things, e.g. ?* instead of '*', etc. – Joey Apr 26 '12 at 21:08
Using Ruby 1.9.3 under Win7, this prints rectangles one after (below) the other, each having ←[2J←[f+------------------+ as the first line. – r.e.s. Apr 27 '12 at 1:35
then change $> << "\e[2J\e[f"+f to 'cls';$><<f (use backticks for cls) – padde Apr 27 '12 at 8:16

Perl 5, 141 characters

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

Does not start on the upper left corner as the example output does, but that is not stated as a requirement.

share|improve this answer

Ruby 1.9, 162 characters

35 chars shy of @Ventero's answer, but I was impressed that I could get it down this far while still using a relatively straightforward approach to the actual logic. The ^[ is a literal ESC (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}
share|improve this answer

R, 233 characters

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")}
share|improve this answer

Another bash entry - 213 204 chars

Not really a prize winner, but it was fun nonetheless. It uses vt100 char sequences for the drawing. (the code reported here uses 215 chars for readability, 2 chars can be removed by escaping, e.g. '*' -> \*

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
share|improve this answer

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

The \e in the line echo -e "\e[$2;$1H$3" can be produced by

echo -e "\x1b"

to replace it. As binary 0x1b it is 3 chars shorter; I count just 1 for "\e", because only the layouting software forces me to use \e.

share|improve this answer
An anonymous user suggested edits to remove the $ symbols inside ((...)) and replace x=$(($x+$p)) with ((x+=p)) and similarly on the following line. (They also suggested using \e for the escape character). – Peter Taylor Apr 27 '12 at 11:20
I would suggest in addition that \* might work as a replacement for "*". – Peter Taylor Apr 27 '12 at 11:28
@PeterTaylor: Thanks to the anonymous user. I incorporated suggestion no 1, and use no 2 in modified form, and yours. – user unknown Apr 27 '12 at 11:34
@userunknown: You're rep of 1,337 needs to be permanently locked in place :P – mellamokb Apr 27 '12 at 19:08
1  
@mellamokb: It's gone. – user unknown Apr 28 '12 at 23:49
show 1 more comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.