SNAKES is a single-player dodging game in which the player controls a horizontal position on a fixed row, moving right by pressing “8” while the position automatically drifts left each frame. Obstacles scroll down the screen from row 21 upward, and collision is detected using SCREEN$ to read character data directly from the display. Three UDGs (\a, \b, \c) are defined via POKEs into USR memory using 24 bytes of DATA, representing the snake-head obstacle and the player’s character in two halves. The score increments each time the player successfully avoids an obstacle, and a high score is tracked across rounds within the same session using the variable HI.
Program Structure
The program is organized into a main game loop, two subroutines, and a UDG initialization block. Control flow is as follows:
- Lines 10–20: REM header; call UDG setup (line 260) and initialize high score.
- Lines 30–120: Game initialization subroutine call (line 220) and the main play loop.
- Lines 130–190: Game-over screen, score display, and restart logic.
- Lines 220–250: Initialization subroutine — sets border, paper, ink, clears screen, resets variables, dimensions
V$. - Lines 260–310: UDG definition subroutine — reads 24 bytes of DATA and POKEs them into the UDG area starting at
USR "\a".
Game Mechanics
The player character occupies column H on row 9/10 of the screen. Movement is entirely horizontal: pressing “8” increments H by 2 (subject to a right-edge guard of V<29, though V is actually the vertical position variable used during init — this guard condition is likely a copy-paste anomaly), and each frame H is unconditionally decremented by 1 if positive, creating automatic leftward drift. The player must press “8” repeatedly to stay in place or move right.
Obstacles (UDG \a) are printed at a random column on row 21. Because the program never explicitly moves them upward, the scrolling effect is achieved entirely by the ZX Spectrum’s built-in scroll triggered by PRINT AT 21,0; followed by a newline via PRINT on line 110, which advances the display and naturally scrolls all content up one row.
Collision Detection
Collision is checked on line 60 using SCREEN$ (10,h). If the character at the player’s position on row 10 is not a space ("" here standing in for a blank cell), the game branches to the game-over routine. This is a common ZX Spectrum BASIC technique that avoids maintaining a separate data structure for object positions, instead reading the display file directly.
UDG Definitions
Three UDGs are defined via 24 bytes of DATA across lines 290–310, covering characters \a, \b, and \c (8 bytes each). The DATA lines contain the literal token U in several positions, which in this context appears to be used as a numeric value. In Spectrum BASIC, an unquoted U in a DATA statement would be evaluated as a variable — if U is uninitialized or zero, those bytes would be 0. Line 320 documents the mapping: A=\a (the falling obstacle), B=\b and C=\c (the two-row player sprite).
Key BASIC Idioms and Techniques
POKE 23692,255on line 100 resets the scroll counter, suppressing the “scroll?” prompt that would otherwise appear after 22 lines of output, allowing uninterrupted scrolling.- The
PAUSE 0:IF INKEY$ <>"" THEN INPUT 1:GO TO 180idiom on line 180 waits for ENTER specifically:PAUSE 0holds until any key, but the subsequent INKEY$ check re-runs the loop unless the key released was nothing (i.e., after ENTER is released).INPUT 1discards the buffered keypress. DIM V$(704)allocates a 704-character string array. Its role is not immediately obvious from the loop logic — it may be intended as a buffer or leftover from a version that stored the screen state.V$is printed in the game-over sequence (line 130), but it is never assigned content, so it will display as 704 spaces.INK 9in the initialization subroutine uses a transparent ink value, a quirk of the Spectrum’s attribute system.
Bugs and Anomalies
- Line 50 uses
AND v<29as a right-boundary guard, butv(lowercase) at this point in the game holds the value 10 (set in line 220 asLET V=10) and never changes during play. The guard is therefore always true (10 < 29), meaning there is no effective right-edge clamp andHcan exceed column 31, potentially causing an out-of-range PRINT error. - Line 250 contains a bare
RETURNwith no precedingGO SUBpath that would naturally reach it — it is a dead code stub, likely a remnant of editing. - As noted,
Uin the DATA statements (lines 290–310) is treated as a variable reference. IfUis zero at the time of reading, those UDG rows will be blank (all pixels off), which may produce incomplete sprite graphics.
Content
Source Code
10 REM SNAKES
20 GO SUB 260:LET HI=0
30 GO SUB 220
40 PRINT AT 9,H;" "
50 LET h=h+2*(INKEY$="8" AND v<29):IF h>0 THEN LET h=h-1
60 IF SCREEN$ (10,h)="" THEN GO TO 130
70 PRINT AT 9,h; INK 6;"\b"; AT 10,h;"\c"
80 PRINT AT 21,0;
90 PRINT TAB INT (RND*31); INK 1;"\a"
100 POKE 23692,255
110 LET sc=sc+1:PRINT
120 GO TO 40
130 PRINT AT 0,0; OVER 1; PAPER 8; INK 2;v$
140 PRINT AT 0,10;"\{18}\{1}GAME OVER\{18}\{0}"
150 PRINT AT 5,7;"YOU SCORED ";SC
160 IF SC>HI THEN LET HI=SC
170 PRINT AT 10,5;"HIGHEST SCORE TODAY ";HI
180 PRINT #0;"PRESS "; PAPER 1;"ENTER"; PAPER 0;" TO PLAY AGAIN ":PAUSE 0:IF INKEY$ <>"" THEN INPUT 1:GO TO 180
190 GO TO 30
200 STOP
210 REM
220 BORDER 0:PAPER 0:INK 9:CLS :LET V=10:LET H=15
230 LET SC=0:RANDOMIZE
240 DIM V$(704):RETURN
250 RETURN
260 FOR A=0 TO 23
270 READ U:POKE USR "\a"+A,U
280 NEXT A:RETURN
290 DATA 255,126,U,60,U,24,U,0
300 DATA 0,99,119,127,62,28,0,U,U
310 DATA 99,119,73,U,127,82,28,0
320 REM A=\a B=\b C=\c
330 SAVE "SNAKES" LINE 10
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
