This is a ZX81/TS1000 falling-blocks arcade game where the player controls a horizontally moving cursor to catch descending items. The screen is set up with inverse-video rows forming a playing field, and the PEEK of system variables 16396/16397 is used to obtain the base address of the display file so that direct POKE operations can manipulate individual character cells. The ball/block (character code 151) falls column by column toward the bottom, and a collision with character 148 triggers a score increment. A countdown timer (variable B starting at 501) drives the game loop, ending with a score display and automatic restart via RUN.
Program Analysis
Program Structure
The program is organised into four logical phases:
- Initialisation (lines 1–7): Resets the score
N, sets the countdownB=501, draws the playing field with inverse-video characters, and sets the paddle positionP=8. - Main game loop (lines 8–100): Decrements the timer, reads the keyboard, moves the falling block down through display memory, and loops back via
GOTO 10. - Catch handler (lines 110–140): Awards a point, and every 112 catches redraws the screen (
GOTO 3); otherwise returns to the game loop. - End screen (lines 200–220): Prints the score, pauses, clears, and restarts with
RUN.
Display File Addressing
The display file base address is obtained at line 8 with:
LET V=PEEK 16396+256*PEEK 16397
System variables at addresses 16396–16397 hold the low and high bytes of the display file start (D_FILE). Adding offsets to V lets the program treat screen memory as a flat array, bypassing BASIC’s own PRINT AT mechanism for speed.
Movement and Collision
The paddle position P is updated each loop iteration at line 30:
LET P=P-1+(INKEY$="")*2-(P=15)+(P=0)
This single expression moves the paddle left when a key is held (subtracts 1 and adds back 2 only when no key is pressed), and clamps P within the range 0–15 using the boolean terms -(P=15) and +(P=0). On ZX81 BASIC, boolean expressions evaluate to 1 (true) or 0 (false), making this an efficient idiom for boundary clamping without IF statements.
The falling block is written at 120+V+P (line 40 — row 7, column P) and then the FOR loop at lines 50–90 steps backward through display memory in strides of 17 (the ZX81 screen width of 32 columns plus one newline byte = 33 bytes per row, but the stride here is 17, suggesting a narrower virtual playfield). At each cell the loop checks for character 148 (the paddle/catcher character) and, on a miss, writes then immediately clears character 151 (the block).
Key Variables
| Variable | Purpose |
|---|---|
N | Player score (caught blocks) |
B | Countdown timer, starts at 501 |
P | Horizontal paddle position (0–15) |
V | Display file base address from D_FILE |
Z | Loop counter / current display memory address |
Notable Techniques
- Boolean arithmetic for clamping: The paddle movement expression exploits ZX81 boolean-as-integer to handle wrapping without branching.
- Direct display POKE: Writing character codes directly into display memory is significantly faster than
PRINT ATand is the standard ZX81 trick for animation. - Screen redraw trigger:
IF INT(N/112)<>N/112tests divisibility by 112 to trigger a full screen refresh, preventing inverse-video rows from being corrupted over time. - Auto-restart:
RUNat line 215 reinitialises all variables and restarts without requiring user input.
Bugs and Anomalies
- The
FORloop stride of-17is unusual. The ZX81 display file uses 33 bytes per row (32 character positions plus a NEWLINE token at the end). A stride of 17 means the loop visits every other row in reverse, but also potentially lands on non-character bytes, which could produce unpredictable graphical artefacts. - Line 220 (
CLEAR) is unreachable: execution flowsRUNat line 215, which restarts the program beforeCLEARcan execute. - The falling block at line 40 is placed at byte offset
120+V+Prelative to the display file, which corresponds to roughly row 3 columnP(120 ÷ 33 ≈ 3.6). The loop then scans back towardV, meaning the “falling” direction is upward in memory terms — this is consistent with the ZX81 display layout where lower addresses appear higher on screen, so visually the block appears to fall downward.
Content
Source Code
1 LET N=0
2 LET B=501
3 FOR Z=0 TO 6
4 PRINT AT Z,0;"%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%="
5 NEXT Z
6 PRINT "% % % % % % % % % % % % % % % % ","\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~"
7 LET P=8
8 LET V=PEEK 16396+256*PEEK 16397
10 LET B=B-1
20 IF B=0 THEN GOTO 200
30 LET P=P-1+(INKEY$="")*2-(P=15)+(P=0)
40 POKE 120+V+P,151
50 FOR Z=120+V+P TO V STEP -17
70 IF PEEK Z=148 THEN GOTO 110
80 POKE Z,151
81 POKE Z,128
90 NEXT Z
100 GOTO 10
110 POKE Z,120
120 LET N=N+1
130 IF INT (N/112)<>N/112 THEN GOTO 10
140 GOTO 3
200 PRINT "YOUR SCORE ";N
205 PAUSE 50000
210 CLS
215 RUN
220 CLEAR
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
