Level 28: Moving Dot

Open the level →Where it fits in the machine →

Task

Goal: Write a program that moves a dot on the screen using the gamepad.

A moving dot needs: coordinates in RAM, gamepad reading, branching on buttons, and a pixel redraw every cycle.

The main idea: a real program is a loop where reading input, branching, and drawing repeat endlessly: state lives in RAM, the gamepad changes it, the display shows it. All the tricks of levels 23–27 converge into one program.

Related Materials

Solution for self-check

Try building the circuit yourself first. The solution below is a way to check yourself if you're stuck or have already solved it.

What you should get: the checkpoint presses "Left": the dot moves from (7,7) to (6,7) and the old pixel goes dark.

In assembly there are no variables — there is a memory map. We ourselves agree: RAM[0] is X, RAM[1] is Y. This agreement holds for the rest of the program: break it in one place and the program silently breaks. The coordinates "live" in RAM, and the code only reads and rewrites them.

1. Store X and Y coordinates in RAM (e.g. RAM[0]=X, RAM[1]=Y). 2. Each step, read gamepad: LDA 254 (port 0xFE). Buttons: bit 0=Up, 1=Down, 2=Left, 3=Right. 3. Update X/Y in RAM based on pressed buttons (compare via SUB+JN/JZ). 4. Clear old pixel: STA 255 with Acc=0. 5. Write new X/Y via ports 252/253. 6. Light pixel: STA 255 with Acc=1. 7. Loop via JMP.

Tip: start with a simple program that draws a dot at a fixed position. The checkpoint will press "Left" and verify that the dot moved from (7,7) to (6,7) while the old pixel went dark.

Complete program (moves the dot with the gamepad; the same program is inserted by the in-game hint button):

; RAM: RAM[0]=X, RAM[1]=Y; constants:
;   RAM[2]=1, RAM[3]=2, RAM[4]=4, RAM[5]=8, RAM[6]=15
; Ports: 252=MatrixX, 253=MatrixY, 254=gamepad, 255=pixel
init:
  LDA 7
  STA 0              ; X = 7
  LDA 7
  STA 1              ; Y = 7
  LDA 1
  STA 2              ; const 1
  LDA 2
  STA 3              ; const 2
  LDA 4
  STA 4              ; const 4
  LDA 8
  STA 5              ; const 8
  LDA 15
  STA 6              ; const 15
loop:
  ; 1. Erase the old pixel
  LDA 0
  ADD 0              ; Acc = X
  STA 252            ; MatrixX
  LDA 0
  ADD 1              ; Acc = Y
  STA 253            ; MatrixY
  LDA 0
  STA 255            ; pixel = 0
  ; 2. Read the gamepad
  LDA 0
  ADD 254            ; Acc = buttons
  STA 7
  JZ draw            ; no buttons — just redraw
  ; Up (bit 0)
  LDA 0
  ADD 7
  AND 2              ; & 1
  JZ chk_dn
  LDA 0
  ADD 1
  SUB 2              ; Y - 1
  AND 6              ; & 15 — wrap around the edge
  STA 1
  JMP draw
chk_dn:
  ; Down (bit 1)
  LDA 0
  ADD 7
  AND 3              ; & 2
  JZ chk_lt
  LDA 0
  ADD 1
  ADD 2              ; Y + 1
  AND 6
  STA 1
  JMP draw
chk_lt:
  ; Left (bit 2)
  LDA 0
  ADD 7
  AND 4              ; & 4
  JZ chk_rt
  LDA 0
  ADD 0
  SUB 2              ; X - 1
  AND 6
  STA 0
  JMP draw
chk_rt:
  ; Right (bit 3)
  LDA 0
  ADD 7
  AND 5              ; & 8
  JZ draw
  LDA 0
  ADD 0
  ADD 2              ; X + 1
  AND 6
  STA 0
draw:
  ; 3. Draw the dot at its new position
  LDA 0
  ADD 0
  STA 252
  LDA 0
  ADD 1
  STA 253
  LDA 1
  STA 255            ; pixel = 1
  ; 4. Delay
  NOP
  NOP
  NOP
  NOP
  JMP loop
HLT

Assembler help →

Check yourself

Where do the dot’s coordinates live between loop iterations?

In RAM: RAM[0]=X, RAM[1]=Y — the program reads and rewrites them every cycle.