8-bit style bouncing ball around a canvas

20

6

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 Flash.

Shaun Bebbers

Posted 2017-02-17T13:56:16.233

Reputation: 1 814

2JavaScript canvas. D'uh. – Matthew Roh – 2017-02-17T14:05:13.007

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. – Shaun Bebbers – 2017-02-17T14:09:26.393

It'd be better if we had a constant pixel size value. – Matthew Roh – 2017-02-17T14:11:15.760

But that depends on what you are outputting and whether or not you are using fixed-width fonts surely? – Shaun Bebbers – 2017-02-17T14:18:17.967

If you want the ball height and width to be a constant then submit your entry on an 8 bit computer like the Sinclair ZX Spectrum or something ;) – Shaun Bebbers – 2017-02-17T14:30:58.840

Have you managed to type it into and run it on that emulator? – Jonathan Allan – 2017-02-17T14:50:10.800

^ A gif with the result would be nice @ShaunBebbers – Luis Mendo – 2017-02-17T14:51:32.587

I'm using my mobile phone; I'll GIF it asap – Shaun Bebbers – 2017-02-17T15:30:39.280

Jonathan Allan: I've typed this program on a real C64 and variants on a VIC-20, PET, ZX81 and Spectrum many times. The program listing works – Shaun Bebbers – 2017-02-17T15:34:45.493

@ShaunBebbers Jonathan's comment was probably along the lines that the emulator doesn't seem to accept pasting, so you have to type it in by hand – Luis Mendo – 2017-02-17T16:31:03.423

Can we use 0 for the ball? – Conor O'Brien – 2017-02-17T16:45:27.633

Yes you may use a zero - whatever you are comfortable with. As long as it bounces around the screen. – Shaun Bebbers – 2017-02-17T17:16:04.287

Yes, you have to type it in by hand to the online emulator as far as I know. If you use more recent versions of VICE you can copy and paste to that. Read the VICE dox to find out how – Shaun Bebbers – 2017-02-17T18:27:55.960

Even if you do copy/paste to VICE it probably won't recognise the {CLR/HOME} from the listing. Change line 10 to 10 PRINT CHR$(147) – Shaun Bebbers – 2017-02-17T18:32:21.320

Actually I made it clear in the question and description "To see this BASIC listing working, you can type it in with this online Commodore 64 emulator providing your browser supports Flash." – Shaun Bebbers – 2017-02-17T19:46:21.103

@ShaunBebbers Yes, it was clear. It's just annoying not being able to paste it :-) – Luis Mendo – 2017-02-17T20:31:33.767

Ah the joys of 8 bit computing. At least the C64 had a real keyboard unlike some machines. – Shaun Bebbers – 2017-02-17T20:34:31.103

4Can we assume the screen size of 1x1 and print o forever? – Matthew Roh – 2017-02-18T05:27:14.670

Yes if you had a 1x1 screen it would print forever, but you wouldn't see it animate either. You'd have an issue with a 20 x 20 screen where it'd bounce corner to corner unless it started from somewhere other than the top left. – Shaun Bebbers – 2017-02-18T07:39:31.787

I can´t get it typed. All my C64s are inoperative and I can´t find the CLR/HOME key in that emulator (on a german keyboard). This thing could really use a screen keyboard. – Titus – 2017-02-21T23:53:02.267

Try print chr$(147) instead of CLR/HOME or press the Home key if you use Windows emulation – Shaun Bebbers – 2017-02-22T07:18:33.613

1

possible duplicate of ASCII Ball in Box Animation

– Titus – 2017-03-02T14:07:48.803

Sorry about the possible duplication - the programming speak is so much different nowadays (scrolly texts are now animated scrolling marquees, for instance). I did a search but probably missed it or searched for the incorrect expression. – Shaun Bebbers – 2017-03-03T08:55:19.447

Btw, IMHO better online demo

– Felix Palmen – 2017-09-04T15:27:07.550

I think this site is quite nice, just uses an emscripten-compiled vice :) – Felix Palmen – 2017-09-04T15:27:48.747

Answers

3

6502 machine code (C64), 90 89 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 

Online demo -|- browse ca65 assembler source

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.

Felix Palmen

Posted 2017-02-17T13:56:16.233

Reputation: 3 866

1It´s not totally independent, is it? I see two absolute LDAs and two STAs. Great work nonetheless! – Titus – 2017-09-04T21:54:55.900

Damn you're right :o I forgot the self modification! I'll update as soon as I'm on the PC. – Felix Palmen – 2017-09-05T05:16:29.450

1@Titus fixed ... and just for fun, added a "better" variant :) – Felix Palmen – 2017-09-05T10:22:33.790

Have you considered packing the sprite? (Hmm ... use the charset ROM?) And I´d prefer inc $d020 over jsr flash ;) hitshimselfwithalargetrout It´s marvellous! – Titus – 2017-09-05T22:26:07.433

@Titus hehe thanks, and I really thought about copying the ball from the charset, but I wanted a big ball :D Packing might work ... using it in place takes 65 bytes right now (63 for the sprite and 2 padding bytes to align it), so maybe it's possible to have packed data + depacking routine in fewer than 65 bytes. – Felix Palmen – 2017-09-06T06:41:37.680

@Titus several attempts later ... I guess it's impossible to create the sprite from fewer than 65 bytes :) But feel free to try yourself ;) – Felix Palmen – 2017-09-06T07:38:34.220

@Titus yes, OS routines for numbers are often useless, they all operate on floats... That's why I implemented my own "double-dabble" routines in this answer :)

– Felix Palmen – 2017-09-06T07:59:19.967

Ok, probably no way to golf with packing. But You could put the sprite in front and run with SYS 49215. Btw I don´t think that the code starts with its own address? – Titus – 2017-09-07T16:05:48.833

1

@Titus would save 2 bytes, yes. As for the load address, it's part of a valid .prg file and from my meta question here I take I have to include it ... could probably leave it out if the code was position independent.

– Felix Palmen – 2017-09-07T16:15:57.713

I´m not 100% sure, but I think it should work well without initializing the position. (Where is that done anyway?) And why do you copy from $0400 to $0400? Remains of an earlier version? – Titus – 2017-09-07T16:38:58.447

@Titus there's very little initialization, but the whole code up to the start label could be dropped if you don't need a clean exit. I consider my character version the code-golf entry, this sprite version was just for fun ;) The loop copying to the same address is for copying the character rom (it switches banks) --- that's absolutely necessary for leaving the system running because the character rom isn't mapped into VIC bank #3 (from $c000). – Felix Palmen – 2017-09-07T16:55:24.487

I know it´s fun; but it´s still fun to golf it down. Loading to the 1st bank would save a bit, but occupy the BASIC RAM. Relocating the BASIC RAM to $0a00 would be an option, but corrupt any prog that´s already loaded, while it´s totally unobtrusive the way it is. Fragile version: load it to $0400 :D – Titus – 2017-09-08T09:56:17.587

@Titus yes, this was the point ... the only "unobtrusive" (to BASIC) way is to use VIC bank #3 (any other VIC bank overlaps with RAM usable from BASIC), so I did it ... and it still affects TI$ because the IRQ frequency isn't exactly the same when synchronized to the VIC (vblank = rasterline #0) as opposed to the default CIA1 timer, but the difference is very small :) – Felix Palmen – 2017-09-08T12:31:37.843

14

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:

Animation of sample run

Mitchell Spector

Posted 2017-02-17T13:56:16.233

Reputation: 3 392

6It hit the exact corner! :O – mbomb007 – 2017-02-21T16:12:39.743

11

CP-1610 assembly, 6764 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

Output

output

Arnauld

Posted 2017-02-17T13:56:16.233

Reputation: 111 334

10

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.

Jack Brounstein

Posted 2017-02-17T13:56:16.233

Reputation: 381

Unfortunately, this is an invalid answer as the ball does not travel diagonally, as required by the challenge. – El'endia Starman – 2017-02-20T01:47:30.950

Did you try it in Microsoft Edge? Chrome doesn't seem to support the direction attribute. – Jack Brounstein – 2017-02-20T02:42:53.287

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 – El'endia Starman – 2017-02-20T02:49:26.610

1+1 for marquee, that's pretty creative! – Metoniem – 2017-02-20T09:27:48.670

Worked in Chrome for me. – ckjbgames – 2017-02-20T15:03:32.320

@ckjbgames You must have a really old version of Chrome, then, considering that the marquee tag is obsolete. – mbomb007 – 2017-02-21T16:14:57.097

@mbomb007 It only partially worked. – ckjbgames – 2017-02-21T16:28:53.997

If it only moved horizontally, it didn't work. – mbomb007 – 2017-02-21T16:30:25.003

Works in Firefox 56 – WORNG ALL – 2017-10-06T19:20:37.970

8

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.

gif of bouncing O

It looks smoother on hardware.

harold

Posted 2017-02-17T13:56:16.233

Reputation: 1 199

Are you sure this is 70 bytes? It looks like less than that. – 12Me21 – 2017-10-06T20:35:53.540

@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. – harold – 2017-10-06T20:47:03.447

Oh, I guess I counted wrong then. – 12Me21 – 2017-10-06T20:50:09.183

7

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.

James Holderness

Posted 2017-02-17T13:56:16.233

Reputation: 8 298

7

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

Example

R. Kap

Posted 2017-02-17T13:56:16.233

Reputation: 4 730

This is code golf, so you'll want to remove Thread.sleep(50). And your golfed and ungolfed programs don't match. – Jakob – 2017-09-04T15:33:25.627

4

Clojure, 398 380 375 bytes

(ns g(:require[quil.core :as q]))(def w 1e3)(def h 1e3)(def f 100)(def b(atom{:x f :y f :n 1 :m 1}))(q/defsketch . :size[w h]:setup #(do(q/text-font(q/create-font""f))(q/fill 255 255 255)):draw #(let[s 9{x :x y :y n :n m :m}@b c(+ x(* n s))u(+ y(* m s))](q/background 0 0 0)(reset! b{:x c :y u :n(if(< 0 c(- w f))n(* -1 n)):m(if(<(+ 0 f)u h)m(* -1 m))})(q/text"O"(:x @b)(:y @b))))

-18 bytes by changing the font name to an empty string to default it, inlining the boundary checks, and fixing the bottom boundary issue (which you can see in the GIF). Fixing that actually saved bytes.

-5 bytes by changing to a more succinct destructuring syntax and shrinking the ball by a pixel.

Uses Quil.

I tried to switch to functional mode, but it required a lot of extra code and ended up being more expensive.

(ns bits.golf.ball-bounce
  (:require [quil.core :as q]))

(def width 1000)
(def height 1000)

(def font-size 100)

; Mutable state holding the properties of the ball. n and m are the directions on the x and y axis.
(def ball (atom {:x 300 :y 600 :n 1 :m 1}))

(q/defsketch b
  :size [width height] ; Window size

  :setup #(do
            (q/text-font (q/create-font "Arial" font-size)) ; Set the font
            (q/fill 255 255 255)) ; And the text color

  :draw
  #(let [speed 9
         ; Deconstruct the state
         {:keys [x y n m]} @ball
         next-x (+ x (* n speed))
         next-y (+ y (* m speed))

         ; I'm adding/subtracting the font-size so it stays in the window properly
         x-inbounds? (< 0 next-x (- width font-size))
         y-inbounds? (< (+ 0 font-size) next-y height)]

     ; Wipe the screen so the ball doesn't smear
     (q/background 0 0 0)

     ; Reset the state
     (reset! ball
             {:x next-x
              :y next-y
              :n (if x-inbounds? n (* -1 n))
              :m (if y-inbounds? m (* -1 m))})

     ; Draw the ball
     (q/text "O" (:x @ball) (:y @ball))))

Ball Bouncing GIF

(Note, the new version doesn't bounce early along the bottom of the screen like it does in the GIF.)

Carcigenicate

Posted 2017-02-17T13:56:16.233

Reputation: 3 295

I just realized I have (+ 0 font-size) in there. That's embarrassing. I'll fix that in the next version. Should save me like 5 bytes. – Carcigenicate – 2017-02-20T02:45:04.407

4

Racket 247 bytes

(let*((w 500)(h(* w 0.6))(x 100)(y 0)(d 10)(e d)(G(λ(t)(set! x(+ x d))(when(or(> x w)(< x 0))
(set! d(* d -1)))(set! y(+ y e))(when(or(> y h)(< y 0))(set! e(* e -1)))
(underlay/xy(rectangle w h"solid""white")x y(circle 10"solid""black")))))(animate G))

Ungolfed:

(require 2htdp/image
         2htdp/universe) 

(let* ((wd 500)            ; define variables and their initial values
       (ht 300)
       (x 100)
       (y 0)
       (dx 10)
       (dy 10)

       (imgfn              ; define function to draw one frame; called repeatedly by animate fn; 
        (λ (t)             ; t is number of ticks till now- sent by animate fn; ignored here;

                           ; update location (x and y values):
          (set! x (+ x dx))
          (when (or (> x wd) (< x 0))
            (set! dx (* dx -1)))             ; invert direction at edges
          (set! y (+ y dy))
          (when (or (> y ht) (< y 0))
            (set! dy (* dy -1)))             ; invert direction at edges

                           ; draw image: 
          (underlay/xy
           (rectangle wd ht "solid" "white") ; draw background
           x y                               ; go to location (x,y)
           (circle 10 "solid" "black")       ; draw ball
          ))))

  (animate imgfn))         ; animates the images created by imgfn (default rate 28 times/sec)

Output:

enter image description here

rnso

Posted 2017-02-17T13:56:16.233

Reputation: 1 635

1Playing racquetball with Racket! – ckjbgames – 2017-02-19T21:52:55.950

That's a good one! – rnso – 2017-02-20T00:35:45.453

"Racket" is derived from "Scheme" programming language: after Scheme (a devious plan) there is Racket (a scam or swindle)! – rnso – 2017-02-21T09:29:06.437

@mso Even better! – ckjbgames – 2017-02-21T13:42:58.343

3

Jelly, 37 bytes

“ñc‘Ọ24ḶŒḄṖ⁸ị⁷x⁸µ80ḶŒḄṖ⁸ị⁶x⁸‘œS.1
Ç1¿

With some help from this answer for getting the loop and escape characters right. Currently it bounces around in a 80x24 screen, but that can be easily modified in the code.

The coördinates in each direction can be represented as elements of two lists [0, 1,..., 24, 23,..., 1] and [0, 1,..., 80, 79,..., 1], let's call them Y and X, that are infinitely repeated. This infinite repetition can be emulated using modular indexing -- using in Jelly. Example: in the ith iteration the ball is at position (X[i%|X|], Y[i%|Y|]) = (iịY, iịX). The moving ball is just the cursor that is put into position by emitting iịY newlines and iịX spaces.

Demo

https://i.gyazo.com/b8eac64097cb6d3a18185877c2f4c945.gif

Explanation

“ñc‘Ọ24ḶŒḄṖ⁸ị⁷x⁸µ80ḶŒḄṖ⁸ị⁶x⁸‘œS.1        Monadic helper link - argument i.
                                         Resets the terminal, prints Y[i] newlines,
                                         X[i] spaces and returns i + 1.
“ñc‘                                     Set the output to [27, 99]
    Ọ                                    Convert to characters and print (\x1bc)
                                          -> Cursor is at position (0,0)
     24Ḷ                                 Lowered range of 24. Yields [0,...,23].
        ŒḄ                               Bounce. Yields [0,...,23,22,...,0].
          Ṗ                              Pop. Yields [0,...,23,22,...,1] = Y.
           ⁸ị                            Modular index i (⁸) into Y. The current
                                         value is the Y coordinate, y.
              x                          Repeat y times
             ⁷                           the newline character ('\n').
               ⁸                         Output that (y times '\n') and continue
                                         with value i.
                                          -> Cursor is at position (0, y)
                µ                        Monadic chain separation.
                 80ḶŒḄṖ                  Same as above, but this time yielding X.
                       ⁸ị                Modular index i into X, yielding the
                                         value for x.
                          x              Repeat x times
                         ⁶               the whitespace character.
                           ⁸             Output that (x times ' ') and continue
                                         with value i.
                                         -> Cursor is at position (x, y), the
                                            final position.
                             œS.1        Wait 0.1 seconds.
                            ‘            Return i + 1.

Ç1¿                                      Main (niladic) link.
 1¿                                      While true.
Ç                                        Call the helper link. The first time
                                         there is no argument and i will be [],
                                         which is cast to 0 when used as integer
                                         (e.g. try ‘¶Ç). After that, the previous
                                         return value (i + 1) is used.

PidgeyUsedGust

Posted 2017-02-17T13:56:16.233

Reputation: 631

2

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 %)

12Me21

Posted 2017-02-17T13:56:16.233

Reputation: 6 110

2

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>

Neil

Posted 2017-02-17T13:56:16.233

Reputation: 95 035

2

PHP, 112 97 94 103 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

Titus

Posted 2017-02-17T13:56:16.233

Reputation: 13 814

1Hi 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. – Christoph – 2017-02-21T07:03:47.267

1Hey @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. – Titus – 2017-02-21T15:56:11.743

We're definitely a good team ;) Strange thing on the copying I've got no idea why. – Christoph – 2017-02-21T16:05:03.763

2

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 ().

marinus

Posted 2017-02-17T13:56:16.233

Reputation: 30 224

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 – 2017-02-21T18:05:31.657

1@wptreanor: fixed – marinus – 2017-02-21T18:08:56.790

cool, excellent work! – ren – 2017-02-21T18:11:45.553

2

Simons´ BASIC (C64), 66 65 bytes

One byte saved thanks @ShaunBebbers.

I need only one line here, because Simons´ Basic has a modulo function.
AfaIk, this requires a physical C64 and a Simons´ BASIC module
(or any other BASIC extension that has a mod function).

0fori=0to623:print"{CLR}":poke1024+40*abs(mod(i,48)-24)+abs(mod(i,78)-39),81:next:goto

Type in these 69 characters:

0fOi=0TO623:?"{CLR}":pO1024+40*aB(mod(i,48)-24)+aB(mod(i,78)-39),81:nE:gO

{CLR} is PETSCII 147, which clears the screen. Use Shift+CLR/HOME to type it in.

bytecount

When saved to disk, it takes 65 bytes, because the commands are tokenized:
for, to, poke, abs, next and goto are one byte each; mod takes two bytes.
That makes 59 bytes of code plus 4 bytes for pointers and 2 bytes for the line number.

For reference, see Mapping the C64 and search for $800 (BASIC Program Text).
(You can find the Video Screen Memory Area at $400.)

breakdown

The program loops I from 0 to 623 (=LCM of 48 and 78 minus 1). In the loop

  • the screen is cleared
  • I gets mapped to 39..0..38 respectively 24..0..23
  • and the blob (PETSCII 81) is put at the corresponding position in the video memory
    (like the original program does).

When the loop is done, the program is restarted by jumping to line 0.

C64 BASIC, 77 76 bytes

0fori=0to623:print"{CLR}"
1poke1024+40*abs(i-48*int(i/48)-24)+abs(i-78*int(i/78)-39),81:next:goto

Unfortunately I need two lines, because even with all possible abbreviations it would take 83 characters - too many to use the C64 line editor:

0fOi=0to623:?"{CLR}":pO1024+40*aB(i-48*int(i/48)-24)+aB(i-78*int(i/78)-39),81:nE:gO

(A hex editor could be used to create a longer line - which would make it 73 bytes.)

Titus

Posted 2017-02-17T13:56:16.233

Reputation: 13 814

1Commodore command separators are : and not ; – Shaun Bebbers – 2017-02-22T10:06:43.247

1Also if you start at line zero, you can simply use goto in your two-liner version, as goto without a number assumes goto 0 on BASIC 2 – Shaun Bebbers – 2017-02-22T10:08:02.103

If you want to get more commands on your C64 BASIC listing, enter it into a C128 in 128 mode, save it to disk and load it back into C64 mode, the C128 has a 160 character limit by default so this barrier can be broken by using Commodore keyword abbreviations. – Shaun Bebbers – 2017-02-22T12:37:41.013

@ShaunBebbers nice to know. It´s been so long. I also wanted to implement this in machine code ... trying to recap on the kernel routines; not sure when I have to backup what registers; the complete kernel listing is online; I just cannot take the time to dig further. Would You like to complete this?

– Titus – 2017-02-22T15:23:35.733

I was going to make a MC version, though I think submitting it to my own challenge would be over-indulgent even for me. The fastest way would be to write the byte directly to the screen from $0400 to $07e7; or use sprites. Using the Kernal with $ffd2 (output accumulator) would work as you can set the X and Y pos on the cursor easily enough (I don't remember the call for that), but you might have to avoid the last character position in case it forces a line feed. – Shaun Bebbers – 2017-02-22T15:38:25.153

@Titus and Shaun, MC version done, feel free to outgolf ... hehe :D I think sprites aren't an option for golfing :o – Felix Palmen – 2017-09-04T15:31:50.277

1

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.

Tristan Batchler

Posted 2017-02-17T13:56:16.233

Reputation: 121

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. – R. Kap – 2017-02-20T03:26:21.103

1

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

draegtun

Posted 2017-02-17T13:56:16.233

Reputation: 1 592

1

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. :)

Bouncing Red Ball

Abel Tom

Posted 2017-02-17T13:56:16.233

Reputation: 1 150

Are import statements necessary to run this program? – user41805 – 2017-02-20T18:44:15.677

@KritixiLithos Yes sir; Updated! you need to include graphics.h. This answer http://askubuntu.com/questions/525051/how-do-i-use-graphics-h-in-ubuntu was helpful.

– Abel Tom – 2017-02-20T18:48:41.270

1

MATL, 42 bytes

1thXH_XI`Xx8E70hZ"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_XI`Xx9E80hZ"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.

Luis Mendo

Posted 2017-02-17T13:56:16.233

Reputation: 87 464

1

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

DrIB

Posted 2017-02-17T13:56:16.233

Reputation: 11

Nice first entry DrlB - could you please include a byte count. I assume this will work on any Speccy including 16K machines? – Shaun Bebbers – 2017-09-04T12:08:25.387

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 – 2017-09-08T01:40:17.370

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 – 2017-09-08T05:00:29.163

1

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();
    }
}

Felix Palmen

Posted 2017-02-17T13:56:16.233

Reputation: 3 866

1

CHIP-8, 36 34 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

12Me21

Posted 2017-02-17T13:56:16.233

Reputation: 6 110

1

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:

Animated screenshot - point

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.

Animated screenshot - zero

Matheus Avellar

Posted 2017-02-17T13:56:16.233

Reputation: 273

0

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

DrIB

Posted 2017-02-17T13:56:16.233

Reputation: 11

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 – Shaun Bebbers – 2017-09-08T08:48:47.243