# 8-bit style bouncing ball around a canvas

Inspired by this listing from the Commodore 64 User's Guide:

10 PRINT "{CLR/HOME}"
20 POKE 53280,7 : POKE 53281,13
30 X = 1 : Y = 1
40 DX = 1 : DY = 1
50 POKE 1024 + X + 40 * Y, 81
60 FOR T = 1 TO 10 : NEXT
70 POKE 1024 + X + 40 * Y, 32
80 X = X + DX
90 IF X <= 0 OR X >= 39 THEN DX = -DX
100 Y = Y + DY
110 IF Y <= 0 OR Y >= 24 THEN DY = -DY
120 GOTO 50


Make a similar program in your chosen language/platform to bounce a ball-alike object around your terminal, screen, canvas or other visual display area.

You don't have to mimic the C64's PETSCII graphics exactly, a simple O or o will do, nor do you have to use the GOTO command if it exists in your language still. As long as your ball starts at the top of your canvas and travels diagonally until it hits a canvas limit, and then bounces accordingly, as follows:

• Travelling downwards and right and hits the bottom of the screen area, bounces up and continues right;
• Travelling up and right and hits the right-most boundary, and bounces left and up;
• Travelling left and up and hits the top, bounces left and down;
• Travelling left and down and reaches the left-most boundary, bounces right and down;
• Hits any corner and reverses direction;

Then we're all good.

You don't have to move the ball 8-pixels at a time either, like is happening in the BASIC listing on the C64; you can move one character block or one pixel at a time, whichever you think is most appropriate.

To see this BASIC listing working, you can type it in with this online Commodore 64 emulator providing your browser supports JavaScript.

• JavaScript canvas. D'uh. Feb 17, 2017 at 14:05
• I'm not sure what you call a screen nowadays. You used to have just the screen and border area viewed through your television set or VDU... and now you've got terminals, windows, canvases, stdout etc... it's all very confusing to me. Feb 17, 2017 at 14:09
• It'd be better if we had a constant pixel size value. Feb 17, 2017 at 14:11
• Can we assume the screen size of 1x1 and print o forever? Feb 18, 2017 at 5:27
• possible duplicate of ASCII Ball in Box Animation Mar 2, 2017 at 14:07

# Bash + Unix utilities, 125 117 bytes

for((x=y=u=v=1;;x+=u,y+=v,u=(x<1||x>=tput cols-1)?-u:u,v=(y<1||y>=tput lines-1)?-v:v)){
tput cup $y$x
sleep .1
}


Animation of sample run:

• It hit the exact corner! :O Feb 21, 2017 at 16:12

## CP-1610 assembly, 67 … 64 62 DECLEs = 78 bytes

This code is intended to be run on an Intellivision. It's using one of its hardware sprites, known as a MOB (for Mobile Object).

A CP-1610 opcode is encoded with a 10-bit value, known as a 'DECLE'. This program is 62 DECLEs long, starting at $4800 and ending at$483D.

### Hexadecimal dump + source

                            ROMW  10            ; use 10-bit ROM
ORG   $4800 ; start program at address$4800

FRAME   EQU   $17E ; frame # ;; ------------------------------------------------ ;; ;; main entry point ;; ;; ------------------------------------------------ ;; main PROC 4800 0001 SDBD ; load Interrupt Service Routine 4801 02B8 002B 0048 MVII #isr, R0 ; into R0 4804 0240 0100 MVO R0,$100  ; update ISR
4806 0040                   SWAP  R0
4807 0240 0101              MVO   R0,     $101 4809 02B9 0208 MVII #$0208, R1    ; initialize R1 = X
480B 02BA 0108              MVII  #$0108, R2 ; initialize R2 = Y 480D 02BB 0001 MVII #1, R3 ; initialize R3 = DX 480F 009C MOVR R3, R4 ; initialize R4 = DY 4810 0002 EIS ; enable interrupts ;; ------------------------------------------------ ;; ;; main loop ;; ;; ------------------------------------------------ ;; 4811 0280 017E @@loop MVI FRAME, R0 ; R0 = current frame # 4813 0340 017E @@spin CMP FRAME, R0 ; wait for next frame 4815 0224 0003 BEQ @@spin 4817 00D9 ADDR R3, R1 ; X += DX 4818 0379 02A0 CMPI #$2A0,  R1    ; reached right border?
481A 0204 0003              BEQ   @@updDx

481C 0379 0208              CMPI  #$208, R1 ; reached left border? 481E 002F ADCR PC 481F 0023 @@updDx NEGR R3 ; DX = -DX 4820 00E2 ADDR R4, R2 ; Y += DY 4821 037A 0160 CMPI #$160,  R2    ; reached bottom border?
4823 0204 0003              BEQ   @@updDy

4825 037A 0108              CMPI  #$108, R2 ; reached top border? 4827 002F ADCR PC 4828 0024 @@updDy NEGR R4 ; DY = -DY 4829 0220 0019 B @@loop ; loop forever ENDP ;; ------------------------------------------------ ;; ;; ISR ;; ;; ------------------------------------------------ ;; isr PROC 482B 01DB CLRR R3 ; clear a bunch of STIC registers 482C 02BC 0020 MVII #$20,   R4

482E 0263           @@clear MVO@  R3,     R4    ; (including background color,
482F 037C 0032              CMPI  #$32, R4 ; border color, etc.) 4831 0226 0004 BLE @@clear 4833 0259 MVO@ R1, R3 ; update X register of MOB #0 4834 0242 0008 MVO R2,$8    ; update Y register of MOB #0
4836 02BB 017E              MVII  #$017E, R3 ; update A register of MOB #0 4838 0243 0010 MVO R3,$10   ; (using a yellow "O")

483A 0298                   MVI@  R3,     R0    ; increment frame #
483B 0008                   INCR  R0
483C 0258                   MVO@  R0,     R3

483D 00AF                   JR    R5            ; return from ISR

ENDP


# HTML (Microsoft Edge/Internet Explorer), 81 bytes

Pretend it's 1998 with these nested <marquee> tags:

<marquee behavior=alternate direction=down><marquee behavior=alternate width=99>O

Tested in Microsoft Edge, though from what I've read IE should also still support marquees. Decidedly does not work in Chrome.

Setting direction=up would save 2 bytes, but break the rule that the ball has to start at the top of the canvas.

• Unfortunately, this is an invalid answer as the ball does not travel diagonally, as required by the challenge. Feb 20, 2017 at 1:47
• Did you try it in Microsoft Edge? Chrome doesn't seem to support the direction attribute. Feb 20, 2017 at 2:42
• Huh, my apologies - it does work in Edge. I can confirm that it does not work in Chrome, and I can attest that it does work in Firefox and Internet Explorer. Three out of four isn't bad (and you only need one for this answer to be valid). +1 Feb 20, 2017 at 2:49
• +1 for marquee, that's pretty creative! Feb 20, 2017 at 9:27
• Worked in Chrome for me. Feb 20, 2017 at 15:03

# TI-BASIC, 71 70

1->A
1->B
1->C
1->D
While 1
ClrHome
Output(B,A,0
A+C->A
B+D->B
If A<2 or A>15
~C->C
If B<2 or B>7
~D->D
End


Quite literal translation, I wouldn't be surprised if there are tricks to make it smaller.

The screen is 16x8 and 1-indexed so the constants are different.

~ is the SourceCoder way to write the negation symbol.

It looks smoother on hardware.

• Are you sure this is 70 bytes? It looks like less than that. Oct 6, 2017 at 20:35
• @12Me21 how many bytes do you count? I get 80 bytes if I save this on a calculator and 10 bytes for an empty program which agrees with my count. Oct 6, 2017 at 20:47
• Oh, I guess I counted wrong then. Oct 6, 2017 at 20:50

# Befunge, 209 bytes

>10120130pppp>"l52?[J2["39*,,,,39*,,,,,,v
v+56/+55\%+55:+1g01*83-"6!"7\-"6!?"8-*86<
>00g1+:55+%\55+/"+!6"-48*,68>*#8+#6:#,_v$v:+g03g01p02+-\g02*2!-*64\*2!:p00:+g02g<$
>10p:!2*\"O"-!2*30g\-+30p"2"::**>:#->#1_^


This assumes a screen size of 80x25, but you can easily tweak the range by replacing the "O" (79) on the last line and the *64 (24) on the second last line (note that the second last line is executed right to left). The speed can also be adjusted by replacing the "2" (50) on the last line.

# Java, 184 176 bytes

class A{public static void main(String[]a)throws Exception{for(int X=1,Y=1,x=1,y=1;;System.out.print("\033["+X+";"+Y+"H"),Thread.sleep(50),X+=x=X%25<1?-x:x,Y+=y=Y%85<1?-y:y);}}


This makes use of ANSI Escape Sequences to relocate the cursor, which is the object that bounces around a 85 x 25 terminal display. Save in a file named A.java.

## Ungolfed

class Terminal_Bouncing_Ball {
public static void main(String[] args) throws InterruptedException {
int X = 0, Y = 0, dx = 1, dy = 1;
while (true) {
System.out.print(String.format("\033[%d;%dH",X,Y));
Thread.sleep(50);
dx = (X < 1) ? 1 : (X > 71) ? -1 : dx;
dy = (Y < 1) ? 1 : (Y > 237) ? -1 : dy;
X += dx;
Y += dy;
}
}
}


## Demo

• This is code golf, so you'll want to remove Thread.sleep(50). And your golfed and ungolfed programs don't match. Sep 4, 2017 at 15:33

# 6502 machine code (C64), 9089 91 bytes

+2 bytes because it needs a load address (not PIC because of self modification)

00 C0 20 44 E5 CA D0 FD C6 FC D0 F9 A2 20 86 FC A9 D8 85 9E A9 03 85 9F A4 CA
18 A5 9E 69 28 85 9E 90 02 E6 9F 88 10 F2 A4 C9 8A 91 9E C9 20 D0 08 E6 C9 E6
CA A2 51 10 D7 A5 C9 F0 04 C9 27 D0 08 AD 2F C0 49 20 8D 2F C0 A5 CA F0 04 C9
18 D0 B4 AD 31 C0 49 20 8D 31 C0 D0 AA


Online demo

Usage: sys49152

I tried hard to reduce size (e.g. NOT using IRQs for timing but stupid empty loops instead), still impossible to reach the level of Titus' golfed C64 BASIC :o oh, well. But it looks less flickering ;)

Explanation: (vice disassembly)

00 C0       .WORD $C000 ; load address 20 44 E5 JSR$E544           ; clear screen
CA          DEX
D0 FD       BNE $C003 ; inner wait (256 decrements) C6 FC DEC$FC
D0 F9       BNE $C003 ; outer wait (32 decrements in zeropage) A2 20 LDX #$20            ; wait counter and screen code for "space"
86 FC       STX $FC ; store wait counter A9 D8 LDA #$D8            ; load screen base address ...
85 9E       STA $9E ; ... -40 (quasi row "-1") ... A9 03 LDA #$03            ; ... into vector at $9e/$9f
85 9F       STA $9F A4 CA LDY$CA             ; load current row in Y
18          CLC                 ; clear carry flag
A5 9E       LDA $9E ; add ... 69 28 ADC #$28            ; ... $28 (40 cols) to ... 85 9E STA$9E             ; ... vector
90 02       BCC $C023 E6 9F INC$9F             ; handle carry
88          DEY                 ; count rows down
10 F2       BPL $C018 A4 C9 LDY$C9             ; load current col in Y
8A          TXA                 ; copy screen code from X to A
91 9E       STA ($9E),Y ; store at position of screen C9 20 CMP #$20            ; screen code was "space"
D0 08       BNE $C037 ; if not, ball was drawn E6 C9 INC$C9             ; next column   | opcodes are modified
E6 CA       INC $CA ; next row | here for directions A2 51 LDX #$51            ; screen code for "ball"
10 D7       BPL $C00E ; and back to drawing code A5 C9 LDA$C9             ; load current column
F0 04       BEQ $C03F ; if zero, change X direction C9 27 CMP #$27            ; compare with last column (39)
D0 08       BNE $C047 ; if not equal, don't change X direction AD 2F C0 LDA$C02F           ; load opcode for X direction
49 20       EOR #$20 ; toggle between ZP INC and DEC 8D 2F C0 STA$C02F           ; store back
A5 CA       LDA $CA ; load current row F0 04 BEQ$C04F           ; if zero, change Y direction
C9 18       CMP #$18 ; compare with last row (24) D0 B4 BNE$C003           ; if not equal, don't change Y direction
AD 31 C0    LDA $C031 ; load opcode for Y direction 49 20 EOR #$20            ; toggle between ZP INC and DEC
8D 31 C0    STA $C031 ; store back D0 AA BNE$C003           ; -> main loop


Just for fun, here's a more professional variant using a sprite for the ball and flashing the border when hit in 385 bytes (containing the sprite data that's used in place):

00 C0 AD 15 D0 F0 30 A9 CC 85 FC A9 04 20 A2 C0 A9 97 8D 00 DD A9 15 8D 18 D0
A9 00 8D 15 D0 8D 1A D0 A2 81 8E 0D DC A2 31 8E 14 03 A2 EA 8E 15 03 58 A6 D6
4C F0 E9 A9 04 85 FC A9 CC 20 A2 C0 A2 31 86 01 A2 10 A9 D0 85 FC B1 FB C6 01
91 FB E6 01 C8 D0 F5 E6 FC CA D0 F0 A9 37 85 01 A9 94 8D 00 DD A9 35 8D 18 D0
8D 27 D0 A2 05 8E F8 CF A2 01 8E 15 D0 8E 1A D0 8E 12 D0 86 FD 86 FE A2 18 8E
00 D0 A2 1B 8E 11 D0 A2 32 8E 01 D0 A2 7F 8E 0D DC AE 0D DC AE 20 D0 86 FB A2
C1 8E 14 03 A2 C0 D0 8A 85 FE 8D 88 02 A9 00 85 FB 85 FD A2 04 A0 00 78 B1 FB
91 FD C8 D0 F9 E6 FC E6 FE CA D0 F2 60 A6 FB 8E 20 D0 CE 19 D0 A5 FD F0 20 AD
00 D0 18 69 04 8D 00 D0 90 03 EE 10 D0 C9 40 D0 2C AD 10 D0 29 01 F0 25 20 38
C1 C6 FD F0 1E AD 00 D0 38 E9 04 8D 00 D0 B0 03 CE 10 D0 C9 18 D0 0C AD 10 D0
29 01 D0 05 20 38 C1 E6 FD A5 FE F0 14 AD 01 D0 18 69 04 8D 01 D0 C9 E6 D0 19
20 38 C1 C6 FE F0 12 AD 01 D0 38 E9 04 8D 01 D0 C9 32 D0 05 20 38 C1 E6 FE 4C
31 EA A9 01 8D 20 D0 60 00 00 00 7E 00 03 FF C0 07 FF E0 1F FF F8 1F FF F8 3F
FF FC 7F FF FE 7F FF FE FF FF FF FF FF FF FF FF FF FF FF FF 7F FF FE 7F FF FE
3F FF FC 1F FF F8 1F FF F8 07 FF E0 03 FF C0 00 7E 00 00 00 00


Start and stop the bouncing ball with sys49152.

• This leaves the C64 BASIC running, that's done by moving the VIC-II address space up to $C000, which requires copying the screen contents and the character set (font). • It hooks into the system IRQ and to avoid flicker, changes the source of this IRQ to the VIC-II graphics chip, so updates are always done between frames. • Glitches: 1. RUN/STOP + RESTORE is broken, don't try. 2. With the VIC-II as IRQ source, the cursor blinks slightly slower and TI$ will lag behind as well.
3. when stopping while the border is flashed (very unlikely but possible), it stays white -- you have to restore it manually.
• It´s not totally independent, is it? I see two absolute LDAs and two STAs. Great work nonetheless! Sep 4, 2017 at 21:54
• Damn you're right :o I forgot the self modification! I'll update as soon as I'm on the PC. Sep 5, 2017 at 5:16
• @Titus fixed ... and just for fun, added a "better" variant :) Sep 5, 2017 at 10:22

# SmileBASIC, 85 74 bytes

SPSET.,9M=MAINCNT
SPOFS.,ASIN(SIN(M/5))*122+192,112+71*ASIN(SIN(M/3))EXEC.


The position of the ball can be modelled with 2 triangle waves, and the shortest way I could find to produce them in SmileBASIC was arcsine(sine(x)). (the algorithm using MOD was longer since SB uses MOD instead of %)

## CSS/HTML, 200 + 7 = 207 bytes

p{position:relative}a{position:absolute;animation:infinite linear alternate;animation-name:x,y;animation-duration:7.9s,2.3s}@keyframes x{from{left:0}to{left:79ch}}@keyframes y{from{top:0}to{top:24em}}
<p><a>O

This version shows you the size of the canvas and also gives the animation a more pixilated feel:

p {
position: relative;
width: 80ch;
height: 25em;
border: 1px solid black;
}
a {
position: absolute;
animation: infinite alternate;
animation-name: x, y;
animation-duration: 7.9s, 2.3s;
animation-timing-function: steps(79), steps(23);
}
@keyframes x {
from {
left: 0;
} to {
left: 79ch;
}
}
@keyframes y {
from {
top: 0;
} to {
top: 24em;
}
}
<p><a>O</a></p>

# Dyalog APL, 44 bytes

{⎕SM∘←0,G←⍺+⍵⋄G∇⍵×1-2×⊃1 G∨.≥G⎕SD⊣⎕DL.1}⍨1 1


Explanation:

• {...}⍨1 1: call the given function with ⍺=⍵=1 1
• ⎕SM∘←0,G←⍺+⍵: store ⍺+⍵ in G, display a 0 at that location in the ⎕SM window.
• ⎕DL.1: wait 1/10th of a second
• ⊃1 G∨.≥G⎕SD: check if G is at the ⎕SM window boundary (1≥G or G≥⎕SD, ⎕SD is the screen dimensions)
• 1-2×: map [1,0] onto [¯1,1], to flip the direction of travel
• ⍵×: multiply the current direction of travel by that
• G∇: recursion, let G be the new location (⍺) and ⍵.... be the new direction (⍵).
• Is this supposed to continuously open and close terminals as it runs? It's quite difficult to stop this from running once it's started, as the terminal closes and reopens every tenth of a second (at least on Windows).
– ren
Feb 21, 2017 at 18:05
• @wptreanor: fixed Feb 21, 2017 at 18:08
• cool, excellent work!
– ren
Feb 21, 2017 at 18:11

# PHP, 1129794103 102 bytes

for(;;usleep(1e5),$i%=624)echo($r=str_repeat)(A^K,99),$r(A^a,abs($i%78-39)),O,$r(A^K,abs($i++%48-24));


bounces a capital O on a 40x25 grid, starting at the top right corner;
prints 99 newlines to clear the screen.

Run with -nr.

A^K = chr(10) = newline
A^a = chr(32) = space

• Hi Titus it's me again. for($d=$e=-1;;usleep(1e5))echo($r=str_repeat)(A^K,99),$r(A^a,$x+=$d*=$x%79?1:-1),O,$r(A^K,$y+=$e*=$y%24?1:-1);. The modulo is false at 0 and N and reverts the direction. Sadly we have to init$d and $e to -1 but still get some savings. $x%79<=>.5 also works for the same bytes. Feb 21, 2017 at 7:03
• Hey @Christoph welcome back. Strange: when I copied Your stuff it had 116 bytes instead of 110. But it inspired me to something a lot shorter. Feb 21, 2017 at 15:56
• We're definitely a good team ;) Strange thing on the copying I've got no idea why. Feb 21, 2017 at 16:05

# QBasic, 71 bytes

DO
CLS
LOCATE 24-ABS(i MOD 46-23),80-ABS(i MOD 158-79)
?"O";
i=i+1
LOOP


This version loops forever, although it might break when i gets too large--I haven't tested. Also, how fast it moves depends on the hardware you use, but on the emulator at Archive.org it runs too fast to see the motion. Therefore, here's a somewhat friendlier version that terminates once the ball gets back to the top left corner:

FOR i=0TO 3634
CLS
LOCATE 24-ABS(i MOD 46-23),80-ABS(i MOD 158-79)
?"O";
z=COS(1)
NEXT


Change the COS(1) to COS(1)+COS(1)+COS(1) (etc.) to slow it down further. Try it here!

### Explanation

Our bounding box is QBasic's standard text mode screen, 80 characters wide by 24 characters tall, 1-indexed. As several other answers have observed, we can calculate the correct x and y coordinates, given a frame number, using modular arithmetic:

Frame i i MOD 46 (i MOD 46)-23 ABS((i MOD 46)-23) y = 24-ABS(...) x = 80-ABS(...)
0 0 -23 23 1 1
1 1 -22 22 2 2
22 22 -1 1 23 23
23 23 0 0 24 24
24 24 1 1 23 25
45 45 22 22 2 46
46 0 -23 23 1 47
47 1 -22 22 2 48
79 33 10 10 14 80
80 34 11 11 13 79

After that it's just an issue of clearing the screen with CLS, moving to the proper coordinates with LOCATE, and printing "O".

# Python 2, 176 168 Bytes

This assumes a terminal size of 80x24. Definitely not optimal but I'm new to golfing so yeah.

import time;x=y=d=e=1
while 1:
m=[[' 'for i in' '*80]for j in' '*24];x+=d;y+=e;m[y][x]='O';time.sleep(.1)
if x%79<1:d=-d
if y%23<1:e=-e
for r in m:print''.join(r)


Thanks to R. Kap for suggesting the x%79<1 instead of x<1or x>79 and ditto for y.

• You can save a few bytes by replacing x<1or x>78 with x%79<0 and y<1or y>22 with y%23<1. Feb 20, 2017 at 3:26

# Rebol/View, 284 266 bytes

rebol[]p: 3x9 d:[3 3]view layout[b: box blue 99x99 effect[draw[circle p 2]]rate :0.01 feel[engage: func[f a e][if a = 'time[case/all[p/x < 2[d/1: abs d/1]p/y < 2[d/2: abs d/2]p/x > 98[d/1: negate d/1]p/y > 98[d/2: negate d/2]]p/x: p/x + d/1 p/y: p/y + d/2 show b]]]]


Ungolfed:

rebol []

p: 3x9     ;; starting position
d: [3 3]   ;; direction

view layout [
b: box blue 99x99 effect [
draw [
circle p 2
]
]

rate :0.01 feel [
engage: func [f a e] [
if a = 'time [
case/all [
p/x < 2  [d/1: abs d/1]
p/y < 2  [d/2: abs d/2]
p/x > 98 [d/1: negate d/1]
p/y > 98 [d/2: negate d/2]
]
p/x: p/x + d/1
p/y: p/y + d/2
show b
]
]
]
]


## C 294 bytes

#include<graphics.h> f(){int d=0;g,x,y,a=0,b=0;initgraph(&d,&g,NULL);x=30;y=30;while(1){x+=6;y+=7;if(y<60)b=0;if(x<60)a=0;if((y>getmaxy()-40)) b=!b;if((x>getmaxx()-40))a=!a;if(b){y-=18;x+=3;}if(a){x-=15;y+=2;}usleep(10000);setcolor(4);cleardevice();circle(x, y,30);floodfill(x,y,4);delay(45);}}


Ungolfed version:

#include<graphics.h>
void f()
{
int d=DETECT,g,x,y,r=30,a=0,b=0;
initgraph(&d,&g,NULL);
x=30;
y=30;

while(1)
{
x+=6;
y+=7;

if(y<60)
b=0;
if(x<60)
a=0;

if((y>getmaxy()-40))
b=!b;

if((x>getmaxx()-40))
a=!a;

if(b)
{
y-=18;
x+=3;
}

if(a)
{
x-=15;
y+=2;
}
usleep(10000);
setcolor(RED);
cleardevice();
circle(x,y,r);
floodfill(x,y,RED);
delay(45);

}

}


## Explanation

• So in order to begin with this, I had to get graphics.h in my /usr/include directory. Therefore, i searched and this is what I found. It is a TurboC Graphics implementation using SDL for Linux. One could also use OpenGL. In windows, I guess it is already installed, not sure about MacOS.
• void initgraph(int *graphdriver, int *graphmode, char *pathtodriver); initialises the system and puts it in a graphics mode, in this case graphics driver is automatically detected. Please refer to this link for more details.
• x and y are coordinates that determines the ball's position.
• a and b are flags, a is set to zero when the x value drops below 60 and b is set to zero when y drops below 60.
• The flags are toggled when x and y exceeds boundary values of window, and the coordinates are accordingly adjusted.
• I put a usleep so that my CPU does not get stressed out.
• One should normally use a closegraph() call, in order to close the window. But it's missing here.

Must be compiled with the linker flag -lgraph

It runs smoother on real hardware. :)

• Are import statements necessary to run this program? Feb 20, 2017 at 18:44
• @KritixiLithos Yes sir; Updated! you need to include graphics.h. This answer askubuntu.com/questions/525051/… was helpful. Feb 20, 2017 at 18:48

# MATL, 42 bytes

1thXH_XIXx8E70hZ"79HZ}&(DH4M\1>EqI*XIH+XH


This uses a 70×16 screen and character O. If you wait for a few bounces you'll see the ball hitting a corner.

Try at MATL Online!

Screen size can be easily modified in the code. The relevant part is 8E70, which pushes 8, doubles it, and pushes 70. For example, for a 80×25 screen replace by 5W80, which pushes 5, squares it, and pushes 80 (or replace by 25 80, but that requires one more byte).

Also, adding tD at the end of the code shows the current position in real time (vertical, then horizontal, 1 1 is upper left). As an example, for a 80×18 screen,

1thXH_XIXx9E80hZ"79HZ}&(DH4M\1>EqI*XIH+XHtD


Try it too!

### Explanation

This uses an infinite loop. Position is kept in clipboard H as a 1×2 vector, and direction is kept in clipboard I as a 1×2 vector with entries 1 or -1.

Each iteration clears the screen, defines a matrix of spaces, writes an O at the relevant position, and displays it. Then the position and directio need to be updated.

Position is 1-based, and thus the edges of the screen are 1 and the maximum screen size. So if position modulo screen size gives 0 or 1 in either the first or second components, which means we have reached a vertical or horizontal edge respectively, that component of the direction vector is negated. After that, the new direction is added to the current position to obtain the new position.

Here's the ZX Spectrum listing.

  10 FOR n=0 to 7
20 READ a: POKE USR "a"+n, a
30 NEXT n
40 DATA 60,126,243,251,255,255,126,60
50 LET x=10:LET y=10:LET vx=1: LET vy=1
60 PRINT AT y,x;"\a"
70 IF x<1 OR x>30 THEN LET vx=-vx
80 IF y<1 OR x>20 THEN LET vy=-vy
90 LET x=x+vx: LET y=y+vy
100 PRINT AT y-vy,x-vx;" ": GO TO 60

• Nice first entry DrlB - could you please include a byte count. I assume this will work on any Speccy including 16K machines? Sep 4, 2017 at 12:08
• Hi this is 201 bytes, you could omit the first 4 lines but then you get just a bouncing "a" character but it saves you 64 bytes. I will try to optimize. This nothing fancy at all and will work on any Spectrum model :)
– DrIB
Sep 8, 2017 at 1:40
• Ok I've managed to cut it down to 185 by condensing the lines a bit without dropping the ball graphics. It's a bit less readable though but it's faster.
– DrIB
Sep 8, 2017 at 5:00

# C + curses, 190 bytes

#include<curses.h>
w;h;x;y;d;main(e){initscr();curs_set(0);getmaxyx(stdscr,h,w);for(d=e;;usleep(20000),mvaddch(y,x,32)){mvaddch(y+=d,x+=e,48);if(!y||y>h-2)d=-d;if(!x||x>w-2)e=-e;refresh();}}


Explanation:

#include<curses.h>
w;h;x;y;d;
main(e)
{
initscr();
curs_set(0);
getmaxyx(stdscr,h,w);

// initialize distances to 1 (e is 1 when called without arguments)
// wait for 1/5 second, then write space character at current pos
for(d=e;;usleep(20000),mvaddch(y,x,32))
{
// advance current pos and write ball character (0)
mvaddch(y+=d,x+=e,48);

// check and change direction:
if(!y||y>h-2)d=-d;
if(!x||x>w-2)e=-e;

// trigger output to screen:
refresh();
}
}


# Lua (LÖVE 2D), 130 bytes

x,y,a,b=0,0,1,1
function love.draw()a=(x<0 or x>800)and-a or a
b=(y<0 or y>600)and-b or b
x=x+a
y=y+b
love.graphics.points(x,y)end


Lua is not the best language when it comes to code golf, but here you go! A few points worth mentioning:

• The default canvas size is 800 x 600. It can be changed in the configuration file, but I didn't see any size restrictions, so I left it as is.

• love.draw() is LÖVE's drawing function and it has a predetermined name. Alternative LÖVE functions that could be used would be love.update(dt) and love.run() -- the first being longer, in bytes, and the latter being shorter, yes, but without a built-in infinite loop. Thus, draw() seems to be our best bet here.

• The above version uses love.graphics.points to draw the ball. Although shorter, I am not sure it is allowed. Here is a GIF of how it runs:

As you can see (or perhaps can't), there is a single pixel moving on the screen. While that saves up bytes, it's not the most satisfying of results.

So I've made an alternative 131 bytes solution:

x,y,a,b=0,0,1,1
function love.draw()a=(x<0 or x>795)and-a or a
b=(y<0 or y>595)and-b or b
x=x+a
y=y+b
love.graphics.print(0,x,y)end


This one uses love.graphics.print -- which prints text -- and a 0 as a ball, making it much more visible and appealing.

# CHIP-8, 3634 28 bytes

FF29 'LDF I,vF //load digit sprite for the value of vF (should be 0)

4000 'SNE v0,0 //if x is 0...
6201 'LD v2,1 //set x velocity to 1
403C 'SNE v0,3C //if x is 3C...
62FF 'LD v2,FF //set x velocity to -1
4100 'SNE v1,0 //if y is 0...
6301 'LD v3,1 //set y velocity to 1
411B 'SNE v1,1B //if y is 1B...
63FF 'LD v3,FF //set y velocity to -1

D015 'DRW v0,v1,5 //draw sprite
D015 'DRW v0,v1,5 //draw sprite again to clear it.
8024 'ADD v0,v2 //add x velocity to x
8134 'ADD v1,v3 //add y velocity to y

1202 'JMP 202 //jump to second instruction


No fancy tricks here...

Requires an interpreter that draws sprites correctly (only one sprite can be drawn per frame, which slows down the program enough for you to be able to see it).

Low quality video

# ZX Spectrum BASIC - 179 bytes

Here it is just condensed a little bit. It's 179 bytes with the ball graphics included

  10 LET a=10: LET b=10: LET c=1: LET d=-1: FOR e=0 TO 7: READ f: POKE USR "a"+e, f: NEXT e
20 DATA 60, 126,243,251,255,255,126,60
30 PRINT AT b,a;"\a"
40 IF a<1 OR a>30 THEN LET c=-c
50 IF b<1 OR b>20 THEN LET d=-d
60 LET a=a+c: LET b=b+d: PRINT AT b-d, a-c;" ": GO TO 30

• Please look at the mark-up used for answers, also by using the character o or O you may be able to save some bytes in the symbolic listing; you are also able to edit previous answers when you have improved solutions, rather than re-answering the same question Sep 8, 2017 at 8:48

## PostScript (GhostScript), 259 bytes

I don't think PostScript was built for animation... improvements welcome!

[/x{4}/y{196}/X{2}/Y{-2}/b{x y 4 currentgray add 0 360 arc fill}/p{/x x X add def}/q{/y y Y add def}/g{setgray}>>begin[/PageSize[320 200]>>setpagedevice{1 g
b p q
x 316 gt x 4 lt or{/X X -1 mul def}if
y 196 gt y 4 lt or{/Y Y -1 mul def}if
0 g b flushpage}loop


Needs GhostScript for flushpage.

(It runs smoother when the screen recorder isn't also running.)