This is a falling-object dodge game where the player controls a character on row 10 using the “M” key to move right while the object drifts leftward automatically. Line 3 executes a machine code routine at address 16514 (the ZX81 display file area) before the main game loop starts. Collision detection is performed by PEEKing the display file pointer registers (16398/16399) and checking whether the character at the player’s position equals 151 (an inverse video character). The score counter F increments each frame via SCROLL, and a row of inverse-space characters at line C creates a visible floor or barrier across the screen.
Program Analysis
Program Structure
The program is divided into a few distinct phases:
- Initialisation (lines 1–4): Sets FAST mode, calls a machine code routine at
USR 16514, then returns to SLOW mode. - Variable setup (lines 20–110): Initialises score
F=0, player rowA=10, player columnB=15, and floor rowC=20. - Main game loop (lines 120–210): Prints the falling object, updates the player sprite, scrolls, draws the floor, handles movement, and checks for collision.
- End-game (lines 220–230): Displays the score and halts.
- Utility lines (240–260): CLEAR, SAVE and RUN, used for program storage and auto-restart.
Screen Layout and Characters
Inverse video characters (written as %X escapes) are used throughout for sprites and the floor line. The player sprite at AT A,B is printed as % (inverse space) to place, then redrawn as %V for the visible character. The falling object is %* (inverse asterisk) printed at a random column on row C each iteration. The floor at row C is a full line of 32 inverse-space characters.
Machine Code Usage
Line 3 executes RAND USR 16514. Address 16514 (hex 4082) lies within the ZX81 display file region. This is a common technique to run a small machine code patch embedded in the display memory or just above the system variables. The exact function is unknown without disassembly, but such routines on ZX81 programs of this era typically modify system variables or set up custom character sets. The surrounding FAST/SLOW pair (lines 2 and 4) ensures the routine executes while the display is blanked.
Collision Detection
Collision is detected at line 210 using a PEEK chain:
PEEK 16398andPEEK 16399read the ZX81 system variableD_FILE(display file start address), low byte and high byte respectively.- The combined address
PEEK 16398 + 256*PEEK 16399gives the start of the display file. - A further
PEEKof that address reads the character at the top-left of the display (or near it — the exact offset depends on the current display state). - If the result equals
151(an inverse-video character code), a collision is flagged and the program jumps to the end sequence.
Note: this technique reads a fixed offset from D_FILE rather than the player’s actual position, which is an approximation and may produce unreliable collision results depending on scroll state.
Player Movement
The player column B drifts leftward each frame unconditionally (line 170): B = B - 1 - INT(RND), giving a random left-drift of 1 or 2 pixels per frame. Pressing “M” moves the player right (line 180): B = B + 3*RND, adding between 0 and 3 columns. The boundary checks (B>4 and B<28) prevent the player from drifting off either edge.
Scoring
The score F is incremented by 1 each pass through the loop at line 140. The SCROLL at line 150 shifts the display content upward each frame, giving a sense of vertical movement and acting as a crude frame timer. The final score is displayed bracketed by asterisks: *score* at line 220.
Key BASIC Idioms
| Line | Idiom | Purpose |
|---|---|---|
130 | PRINT AT A,B;"% " | Erase previous player position with inverse space before redraw |
165 | PRINT AT 21,31;AT 21,0; | Moves print position without outputting visible characters; cursor housekeeping |
190 | PRINT AT A,B;"%V" | Draw player sprite at updated position |
200 | PRINT AT 11,B; | Reposition print cursor mid-screen without output |
Anomalies and Notes
- The REM statement at line 1 contains what appear to be block graphic characters and inverse-video text, likely used as a visual banner or stored data header rather than meaningful documentation.
- The collision detection via
PEEK(PEEK 16398+256*PEEK 16399)reads a single fixed byte at the start of the display file rather than the specific cell under the player, making it an imprecise heuristic. - Line 240 (
CLEAR) and line 260 (RUN) are never reached during normal execution (the program STOPs at line 230), and serve only as tape-save utilities. - The
SAVE "1027%0"at line 250 saves the program with an inverse-zero in the filename, which on the ZX81 acts as an auto-run flag when loaded from tape.
Content
Source Code
1 REM Y% \.'\. :%KNOT $TAB \@@RND\: TAB \'.RNDTAN
2 FAST
3 RAND USR 16514
4 SLOW
20 LET F=0
80 LET A=10
90 LET B=15
100 LET C=20
110 SLOW
120 PRINT AT C,RND*30;"%*"
130 PRINT AT A,B;"% "
140 LET F=F+1
150 SCROLL
160 PRINT AT C,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
165 PRINT AT 21,31;AT 21,0;
170 IF B>4 THEN LET B=B-1-INT (RND)
180 IF INKEY$="M" AND B<28 THEN LET B=B+3*RND
190 PRINT AT A,B;"%V"
200 PRINT AT 11,B;
210 IF PEEK (PEEK 16398+256*PEEK 16399)<>151 THEN GOTO 120
220 PRINT "*";F;"*"
230 STOP
240 CLEAR
250 SAVE "1027%0"
260 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
