TRAP is a maze-navigation game where the player moves a cursor through a bordered playfield using keys 5, 6, 7, and 8, avoiding an inverse-video wall character (character code 128) while chasing or avoiding a randomly placed “+” marker. The program uses PEEK of the system variables at addresses 16398 and 16399 to read the ZX81’s display file pointer, then peeks the character currently under the cursor to detect collisions with the border. Movement is mapped to the familiar ZX81 directional keys: 5 (left), 6 (down), 7 (up), and 8 (right). A move counter is maintained in variable A, which is printed when the player hits a wall, giving a score. The random marker “+” is drawn with a slight random walk offset using RND<0.5 expressions as Boolean integers.
Program Analysis
Program Structure
The program is a single-screen maze/trap game with a straightforward linear flow: setup and border drawing, then a game loop with collision detection, and finally a score display and replay prompt.
- Lines 0–30: REM header, initialisation of move counter
A=0(viaNOT PI), and drawing the top and bottom border rows using inverse-video characters. - Lines 40–60: Draw the left and right border columns using a FOR loop, printing
%(inverse space) at column 0 and column 12. - Lines 70–80: Randomly place the target
+marker within the playfield bounds (X: 1–11, Y: 3–13). - Lines 90–180: Main game loop — print player cursor, detect wall collision, move the random marker, count moves, read directional key input, update player position.
- Lines 190–210: End-of-game: print move count, prompt for replay, CLS and STOP or loop back via
RUN. - Line 215: SAVE line for program persistence.
Collision Detection via PEEK
The collision check at line 100 is the most technically interesting part of the program. It reads the ZX81 display file address from system variables at 16398 (low byte) and 16399 (high byte), then peeks the character code at that address — which corresponds to the character currently at the cursor position (AT Y,X) after the PRINT AT Y,X; at line 90 has moved the print position. Character code 128 is the inverse space (solid block), used for the border. If the player has moved onto a border cell, the game ends by jumping to line 190.
The formula PEEK (PEEK 16398 + 256*PEEK 16399) reconstructs the 16-bit display file pointer from the two system variable bytes and dereferences it to read the screen character at the current print position.
Key BASIC Idioms
NOT PIevaluates to 0 (since PI is non-zero, NOT PI = 0), used as a readable way to write the integer zero for initialisingAand loop bounds.VAL "expression"is used throughout for numeric literals (e.g.,VAL "14",VAL "INT (RND*11)+1"). On the ZX81, this saves memory compared to storing the tokenised number with its 5-byte floating-point representation; for complex expressions like line 70–80 it also allows RND to be evaluated at runtime via VAL.SGN PIevaluates to 1, used in line 120 (A=A+SGN PI) to increment the move counter by 1.- Boolean arithmetic:
(A$="8")-(A$="5")and similar expressions in lines 160–170 use the fact that ZX81 BASIC returns 1 for true and 0 for false comparisons, giving a delta of +1, 0, or −1 for directional movement. RND<.5in line 110 produces a random Boolean (0 or 1) used to give the+marker a random walk, shifting it up/down or left/right by at most 1 cell each move.
Inverse Video and Display
The % prefix in the source (e.g., % ) represents inverse-video characters, used to draw the border walls. Character code 128 (inverse space) forms the solid border. The REM line 0 also uses inverse characters to display the title “TRAP” in a decorative header block.
The AND Clause in Line 110
Line 110 uses the expression "% " AND PEEK(...) <> 21. On the ZX81, X AND condition returns X if the condition is true, or 0 (empty string for strings) if false. Character code 21 is the ZX81 code for +, so this prevents the random marker from being redrawn as inverse space if the player is standing on it — it prints the inverse space only if the current character is not a +. This is a compact conditional print technique common in ZX81 BASIC.
Replay Logic
The end-of-game section at lines 195–210 uses a two-stage check for “N”: first at line 199 via INKEY$="N" (immediate), then after a long PAUSE 4E4 (approximately 6.5 minutes at 50 Hz, effectively waiting for a key), a second check at line 201. If neither triggers STOP, the program CLSes and STOPs anyway at line 210, with RUN at line 220 only reachable if execution somehow falls through — in practice the replay path for “Y” relies on the PAUSE expiring and INKEY$ not returning “N”, then falling through to CLS/STOP. This logic is slightly convoluted; a “Y” response causes the pause to expire (the player presumably presses another key to cancel the PAUSE early), INKEY$ at 201 is not “N”, and execution reaches line 205 CLS then 210 STOP — meaning the game does not actually loop back automatically via RUN, and a fresh RUN must be issued manually or via the SAVE autorun mechanism.
Potential Anomalies
- The playfield X range (1–11) and Y range (3–13) are designed to stay inside the border, but the player movement in lines 160–170 has no bounds checking — it is possible to move through the border and out of the bordered region if the collision detection is somehow bypassed. In practice the PEEK check at line 100 catches border entry.
- The
PAUSE 4E4(40000 frames ≈ 800 seconds at 50 Hz) is an unusual delay for a replay prompt; it acts as a very long wait rather than a true PAUSE 0 idiom. - The display file pointer approach for collision detection depends on the ZX81 system variable layout and would not be portable to other systems.
Content
Source Code
0 REM \##\##\##\##%T%R%A%P\##\##\##\## BY DILWYN JONES
10 RAND
20 LET A=NOT PI
30 PRINT AT VAL "14",NOT PI;"% % % % % % % % % % % % % ";AT VAL "2",NOT PI;"% % % % %T%R%A%P% % % % % "
40 FOR X=NOT PI TO VAL "10"
50 PRINT "% ";TAB VAL "12";"% "
60 NEXT X
70 LET X=VAL "INT (RND*11)+1"
80 LET Y=VAL "INT (RND*11)+3"
90 PRINT AT Y,X;
100 IF PEEK (PEEK 16398+256*PEEK 16399)=128 THEN GOTO 190
110 PRINT "+";AT Y+(RND<.5)-(RND<.5),X+(RND<.5)-(RND<.5);"% " AND PEEK (PEEK 16398+256*PEEK 16399)<>21
120 LET A=A+SGN PI
130 LET A$=INKEY$
140 IF A$<"5" OR A$>"8" THEN GOTO 130
150 PRINT AT Y,X;" "
160 LET X=X+(A$="8")-(A$="5")
170 LET Y=Y+(A$="6")-(A$="7")
180 GOTO 90
190 PRINT A
195 PRINT AT 20,0;"%A%N%O%T%H%E%R% %G%O%? (Y/N)"
199 IF INKEY$="N" THEN STOP
200 PAUSE 4E4
201 IF INKEY$="N" THEN STOP
205 CLS
210 STOP
215 SAVE "1021%2"
220 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
