This is an arcade-style dodging game where the player moves a car left and right across the bottom of the screen to avoid rapidly changing road conditions. The program defines three custom UDG characters (UDGs “a”, “b”, and “c”) via POKE into USR addresses, using DATA blocks containing pixel patterns. Collision detection is performed using SCREEN$ and ATTR checks at line 120 and 155 rather than coordinate arithmetic, a common Spectrum BASIC technique. The title screen loops with a randomized border color effect via OUT 254 and plays continuous BEEP tones while waiting for a keypress on keys “5” or “8”. A high-score melody is stored as NOTE/DURATION pairs in DATA statements starting at line 9040 and replayed via BEEP in a READ loop.
Program Analysis
Program Structure
The program is organized into several functional regions:
- Lines 1–10: Initialization — calls UDG setup subroutine at 8010, dimensions the screen buffer string
i$(704 chars = 22 rows × 32 cols), sets high scoreh=100, jumps to the attract loop. - Lines 20–160: Main game loop — resets score and positions, cycles through 11 scoring rounds (FOR s=0 TO 10), moves the falling object, reads player input, checks for collision.
- Lines 200–243: End-of-round and attract screen — shows score, plays death tune, branches to high-score routine if appropriate, redisplays title and waits for “5” (play) or “8” (toggle noise).
- Lines 245–249: Noise-off wait state — waits for “5” to play or “8” to resume noise loop.
- Lines 500–550: High-score celebration — prints congratulatory message, plays a tune from DATA, updates
h. - Lines 8010–8070: UDG loader — pokes pixel data into UDG addresses for characters “a”, “b”, “c”.
- Lines 9040–9080: Music DATA for high-score tune (note, duration pairs).
- Lines 9500–9510: Screen-clear subroutine — uses
i$to OVER 1 print 704 spaces, then CLS, resetting attributes cleanly. - Line 9998: SAVE with auto-run.
UDG Character Definitions
Lines 8010–8070 define three UDGs by reading DATA bytes and POKEing them into memory starting at USR "a" through USR "c"+7. The loop iterates over all 24 bytes (3 UDGs × 8 bytes each).
| UDG | Data (hex approx.) | Role |
|---|---|---|
| \a (UDG “a”) | 0,62,8,62,28,62,28,0 | Falling ball/object |
| \b (UDG “b”) | 255,170,213,170,213,170,213,255 | Left half of paddle |
| \c (UDG “c”) | 255,171,85,171,85,171,85,171,255 (9 bytes — see anomaly) | Right half of paddle |
Note: the DATA block for UDG “c” at line 8060 contains nine values rather than eight. The loop runs from USR "a" to USR "c"+7, which is exactly 24 iterations, so the ninth value (171) is read but never POKEd — it is effectively ignored. This is a minor data anomaly but causes no runtime error.
Game Mechanics
The falling object’s column c starts at 12 and is fixed; its row r is updated each iteration with a random walk: r decrements if rnd=1 and r>1, or increments if rnd=0 and r<20. This produces a side-to-side drift rather than a downward fall — the variable names r (row) and c (column) are used in a somewhat reversed sense from convention.
Player input is read at line 110: keys “5” (left) and “8” (right) move the catcher column c. The program also polls PEEK 23560 (the last key pressed system variable) to detect key 9 (ASCII 57) as a repeat-prevention guard, then resets it to 54 (key “6”) at line 115 — an unusual choice for debouncing.
Collision Detection
Two checks are used in sequence:
- Line 120:
SCREEN$ (16,c)— if the cell at the car’s screen position is not a space, a collision is flagged and the game jumps to line 200 (game over). A non-space result means the paddle is under the ball. - Line 155:
ATTR (16,c)— checks the attribute byte; value 122 corresponds to BRIGHT 1, PAPER 4, INK 2 (the wall’s color scheme). If the attribute doesn’t match, the car crashed and the game ends.
Using both SCREEN$ and ATTR together provides a more robust test than either alone, though in practice the SCREEN$ check at line 120 will catch most misses before line 155 is reached.
Screen-Clear Subroutine (Line 9500)
Rather than simply calling CLS, this subroutine PRINTs the 704-character string i$ (initialized as spaces by DIM) with OVER 1 at position 0,0, effectively XORing the existing screen contents before clearing. This technique removes any lingering INK/PAPER attribute color bleed that a plain CLS might leave in certain display states. It also resets POKE 23624,0 (the scroll counter).
Attract Screen and Sound Loop
The attract loop at lines 240–249 plays a sweeping BEEP tone (notes 3 to 6, step 0.5) while randomly changing the border color via OUT 254, INT(RND*7). Two states are implemented: noise-on (line 240 loop) and noise-off (lines 247–249 wait loop), toggled by pressing “8”. Pressing “5” at any point jumps to line 20 to start the game.
High-Score Routine
The high-score subroutine (lines 500–550) plays a 15-note melody stored as interleaved NOTE, DURATION pairs in DATA lines 9040–9080. The READ loop at line 540 uses a slightly unusual construction: IF INKEY$="" THEN NEXT n: GO TO 510 — note that line 510 does not exist, which causes the program to fall through to the next available line (line 530 area). This is a deliberate GO TO non-existent line technique to restart the display portion without re-entering the subroutine fully. However, there is a potential issue: RESTORE 9040 is called each time, and the loop variable n is reused, which could interact with the outer game loop’s use of n in some edge cases.
Notable BASIC Idioms
- Boolean arithmetic for movement:
r=r-(rnd=1 AND r>1)+(rnd=0 AND r<20)uses the Spectrum’s TRUE=1/FALSE=0 convention to avoid IF statements. - Similarly,
c=c+(INKEY$="8")-(INKEY$="5")moves the paddle in one expression. POKE 23692,12sets the scroll count to suppress the “scroll?” prompt during the game loop.- The title screen text at line 235 uses block graphic escape sequences to render a decorative logo banner.
Content
Source Code
1 GO SUB 8010
10 DIM i$(704): LET h=100: GO TO 230
20 GO SUB 9500
30 LET sc=0: LET r=10: LET c=12
40 POKE 23692,12
50 FOR s=0 TO 10
60 LET rnd=INT (RND*2)
70 LET r=r-(rnd=1 AND r>1)+(rnd=0 AND r<20)
80 PRINT AT 16,c; BRIGHT (sc>4); PAPER 7; INK 2;"\a"
90 PRINT AT 21,r; BRIGHT 1; INK 2; PAPER 4;"\b\c"; PAPER 7;TAB r+6; PAPER 4;"\b\c"
100 PRINT
110 LET c=c+(INKEY$="8")-(INKEY$="5"): IF PEEK 23560=57 THEN GO TO 110
115 POKE 23560,54
120 IF SCREEN$ (16,c)<>" " THEN GO TO 200
130 LET sc=sc+1
140 BEEP .005,s
150 NEXT s
155 IF ATTR (16,c)<>122 THEN GO TO 200
160 GO TO 40
200 PRINT AT 16,c; FLASH 1; INK 0; PAPER 4;"\a"
205 PRINT AT 10,10; INK 6; PAPER 2; FLASH 1;"You scored ";sc;AT 12,9;"High score:";h
210 FOR n=10 TO 40 STEP .4: BEEP .001,n: NEXT n
220 IF sc>h THEN GO SUB 500
230 GO SUB 9500: PRINT AT 13,0; FLASH 1; INK 5; PAPER 1;" Press '5' to play or '8' to stop/re-start noise.Use '5' & '8' to move left or right ";AT 1,10;"High score:";h
235 PRINT AT 5,0; INK 2; PAPER 5;" \:'\'' \:'\': \:'\': \:'\'' \: \ : \:'\'' \:'\': \: \:'\:' \:'\': \''\': \:'\': \:'\'' \:'\:' \''\'' \' \'' \' \ ' \''\'' \' \ ' \''\'' \' \'' "
240 POKE 23560,0: FOR n=3 TO 6 STEP .5: BEEP .007,n: OUT 254,INT (RND*7): NEXT n
241 IF PEEK 23560=56 THEN PAUSE 0: GO TO 245
242 IF PEEK 23560=53 THEN GO TO 20
243 GO TO 240
245 POKE 23560,0
247 IF PEEK 23560=53 THEN GO TO 20
248 IF PEEK 23560=56 THEN GO TO 240
249 GO TO 247
500 GO SUB 9500: PRINT AT 10,1; FLASH 1; PAPER 2; INK 4;" A high score! "
530 PRINT AT 12,5; PAPER 5; INK 3; FLASH 1;"The high score was:";h;AT 14,5;"The high score is :";sc;AT 16,10;"Press a key"
540 RESTORE 9040: FOR n=1 TO 15: READ z: READ x: BEEP x,z: IF INKEY$="" THEN NEXT n: GO TO 510
550 LET h=sc: RETURN
8010 FOR n=USR "a" TO USR "c"+7
8020 READ a: POKE n,a
8030 NEXT n
8040 DATA 0,62,8,62,28,62,28,0
8050 DATA 255,170,213,170,213,170,213,255
8060 DATA 255,171,85,171,85,171,85,171,255
8070 RETURN
9040 DATA 0,.3,0,.2,5,1.25
9050 DATA 0,.3,5,.18,9,1.25
9060 DATA 0,.3,5,.18,9,.4
9070 DATA 0,.3,5,.18,9,.4
9080 DATA 0,.3,5,.18,9,1.5
9500 FLASH 0: BRIGHT 1: PAPER 7: INK 1: BORDER 0: PRINT AT 0,0; OVER 1;i$: BRIGHT 0: BORDER 0: CLS : POKE 23624,0
9510 RETURN
9998 SAVE "crasher" LINE 9999
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

