This program implements a simple dodge/catch game where the player moves a marker left and right across the bottom of the screen to intercept falling objects. The player character is displayed as an inverse “Y” character and moves via the Z and C keys, while falling objects (displayed as “**”) descend one row per iteration using the SCROLL command. Collision detection is performed by directly reading display memory: lines 101–102 calculate the display file address via PEEK 16396/16397 and check whether the character at the player’s screen position matches character code 23 (the “**” asterisk). Each successful catch increments a hit counter H, and after 50 scroll cycles the score is printed and the program stops.
Program Analysis
Program Structure
The program is divided into a few logical phases:
- Initialisation (lines 1–30): Sets hit counter
H=0, player positionP=5, and draws a column of block-graphic “wall” characters at column 15 using a shortFORloop. - Main game loop (lines 35–110): Runs for 50 iterations. Each iteration spawns a falling object, scrolls the screen, reads player input, performs collision detection, and briefly flashes the player sprite.
- End of game (lines 120–130): Prints the hit counter and stops.
- Collision/hit handler (lines 400–450): Prints a “BANG” message, pauses, increments
H, and jumps back into the middle of the main loop at line 40.
Display Initialisation
Lines 10–30 draw eight rows of the ▌ block graphic (ZX81 character \ :) at TAB column 15, establishing a right-hand boundary marker before the game begins.
Falling Object Logic
At line 40, the new horizontal position of the falling object is computed as A = INT(P + RND*5 - 2), biasing the object toward the player’s current position with a small random offset. Line 41 clamps A to the valid range 0–14 by replacing out-of-range values with a fully random column. The object is printed as ** at row 8, column A.
Scrolling and Player Movement
The SCROLL command at line 50 moves all display content up by one character row, causing the object to descend visually over successive iterations. The player sprite is erased at its previous position (AT 3,P;" ") before scrolling, then redrawn as an inverse %Y at line 105. Movement keys Z (left) and C (right) are read via INKEY$ at lines 70–80 with boundary checks to keep P within 0–14.
Collision Detection via Display File PEEK
This is the most technically notable aspect of the program. Lines 101–102 implement collision detection by inspecting the display file directly:
- Line 101:
P1 = PEEK 16396 + 256 * PEEK 16397reads the system variableD_FILE(at addresses 16396–16397), which holds the start address of the display file. - Line 102:
PEEK (P1 + 1 + P + 3*17)reads the character at screen row 3 (the player row), columnP. The formula adds 1 (for the newline byte at the start of each row), then3*17bytes to skip three complete rows (each row is 17 bytes: 16 character cells plus one newline), plusPfor the column offset. - If the byte equals 23 (the character code for
*on the ZX81), a collision is detected and execution jumps to line 400.
This technique avoids any coordinate-tracking variables for the falling object by reading back what is actually on screen, a common ZX81 optimisation.
Hit Counter and Loop Re-entry
On a successful hit, line 430 increments H and line 450 jumps to line 40 — back into the middle of the FOR I=1 TO 50 loop, bypassing NEXT I. This means the loop counter I is not incremented on a hit, effectively giving the player a “free” iteration. Whether intentional or a minor oversight is unclear.
Variable Summary
| Variable | Purpose |
|---|---|
H | Hit (catch) counter |
P | Player column position (0–14) |
I | Main loop counter (1–50) |
A | Falling object column position |
P1 | Display file base address (from D_FILE) |
Bugs and Anomalies
- The
GOTO 40at line 450 re-enters theFORloop body without incrementingI, so a hit does not consume a turn — the 50-turn limit is effectively extended by the number of hits. - The
PAUSE 15at line 106 and the absence of any delay elsewhere means game speed is tied to the brief flash of the player sprite rather than a consistent frame rate. - Lines 460–480 (
CLEAR,SAVE,RUN) are unreachable dead code following theSTOPat line 130.
Content
Source Code
1 LET H=0
5 LET P=5
10 FOR I=1 TO 8
20 PRINT TAB 15;"\ :"
30 NEXT I
35 FOR I=1 TO 50
40 LET A=INT (P+RND*5-2)
41 IF A<0 OR A>14 THEN LET A=INT (RND*15)
45 PRINT AT 8,A;"**";AT 8,15;"\ :";AT 3,P;" "
50 SCROLL
70 IF INKEY$="Z" AND P<>0 THEN LET P=P-1
80 IF INKEY$="C" AND P<>14 THEN LET P=P+1
101 LET P1=PEEK 16396+256*PEEK 16397
102 IF PEEK (P1+1+P+3*17)=23 THEN GOTO 400
105 PRINT AT 3,P;"%Y"
106 PAUSE 15
110 NEXT I
120 PRINT H
130 STOP
400 PRINT AT 2,0;"******BANG******"
410 PAUSE 50
430 LET H=H+1
450 GOTO 40
460 CLEAR
470 SAVE "1031%0"
480 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
