CRASHER is a scrolling-screen arcade game in which the player steers a “V” character left and right using the 5 and 8 keys, crashing into alphanumeric characters to score points while avoiding inverse-video characters that end the game. The game loop uses SCROLL to advance the play field upward and places random characters on the bottom row using CHR$ with a probability-weighted inverse-video flag (128 AND RND<0.2). Player collision detection is performed by PEEKing the display file address stored at system variables 16398–16399, checking the ASCII value of whatever character occupies the player’s screen position. The title screen animates the word “CRASHER” scrolling in from both the top and bottom of the screen simultaneously, using FAST/SLOW toggling for a flicker effect, and the game tracks a high score across multiple plays in variable HS.
Program Analysis
Program Structure
The program is divided into several functional blocks:
- Lines 0–10: Initialisation and jump to the animated title sequence at line 9000.
- Lines 20–55: Instructions prompt and routing (Y/N input loop).
- Lines 60–155: Instructions display with delays via the
GOSUB 9900delay routine. - Lines 160–290: Main game loop — player movement, scrolling, random character placement, and collision detection.
- Lines 290–420: Game-over screen, high score update, and replay prompt.
- Lines 2000–2699: Quit/end animation sequence with a “crash” graphic and
STOP. - Lines 2700–2740: Subroutine called on hitting an inverse character — FAST/SLOW flicker and “CRASH” message.
- Lines 9000–9130: Animated intro: “CRASHER” scrolls in from top and bottom simultaneously, then jumps to line 11 (which routes to line 20, the instructions prompt).
- Lines 9900–9920: General-purpose delay loop (50 iterations).
- Lines 9990–9993: Utility lines:
STOP,CLEAR,SAVE,RUN.
Game Loop Logic
The main loop runs from line 210 to 280. Each iteration:
- Prints a random character at the bottom of the screen (line 220). The character is either a normal printable character (CHR$ 1–63) or an inverse-video version if
RND<0.2, achieved by adding 128 using the Boolean expression(128 AND RND<0.2). - Calls
SCROLLto advance the field upward (line 230). - Reads the 5 and 8 keys to update horizontal position
X(line 240), using Boolean arithmetic to clamp within columns 0–19. - Prints the player “V” and positions the cursor at
Y+1,X(line 250). - PEEKs the display file to detect collision (lines 260–279).
- Increments frame counter
Fand loops untilF=100(lines 200–280).
Collision Detection via PEEK
Collision is detected at line 260 using the ZX81 system variables at addresses 16398 and 16399, which together hold the start address of the display file (D_FILE). The expression PEEK 16398 + 256*PEEK 16399 reconstructs the 16-bit pointer. PEEKing that address reads the character code of whatever is at the top-left of the display file, but because the cursor was left positioned at AT Y+1,X after printing the “V”, this effectively reads the character immediately below the player sprite — the cell into which the player is about to scroll.
- If the value is less than 64 (a normal printable character), its code is added to the score
S(line 270). - If the value is greater than 127, it is an inverse-video character; the flash/crash subroutine at 2700 is called (line 274) and the game ends (line 279 jumps to 290).
Notable Techniques
Boolean arithmetic for movement and character generation: Line 240 uses (INKEY$="8" AND X<19) and (INKEY$="5" AND X>0) as 1/0 values to increment or decrement X, a compact idiom. Line 220 uses (128 AND RND<0.2) similarly to conditionally set the inverse-video bit.
FAST/SLOW toggling for visual effect: The crash subroutine (lines 2700–2730) and parts of the quit animation (lines 2060–2090) toggle between FAST and SLOW modes in a loop, producing a screen-flicker effect that simulates an alarm or explosion.
Simultaneous top/bottom title animation: Lines 9020–9050 use a single FOR G loop to print “CRASHER” at both AT G,11 and AT 20-G,11, moving the two copies toward the centre of the screen symmetrically.
POKE 16384,74: At line 2150, the program POKEs the value 74 into address 16384. On the ZX81, address 16384 is the first byte of the system variable area (ERR_NR). Writing 74 sets the error code to 73 (value is stored as error−1), which corresponds to a specific system state; this is used here as a programmatic way to leave a particular condition before the subsequent STOP.
Flow Control and Routing
Line 9130 executes GOTO 11, which is a non-existent line number. The interpreter advances to the next higher line, which is line 20 (the instructions prompt). This is a deliberate and well-known ZX81 technique for falling through to the next defined line without hard-coding its number.
The GO TO VAL "number" idiom is not used here; all GOTO and GOSUB targets are literal. The replay prompt at line 400 sends the player back to line 155 (skipping the instructions display but still performing the delay and “READY??” message) rather than line 60, saving the full instructions re-display on replay.
Bugs and Anomalies
- Line 51 is referenced in line 40 (
IF U$="Y" THEN GOTO 51) but does not exist. Execution falls through to line 55, then to line 60 ifU$is not empty. The effect is that entering “Y” also shows instructions, which appears to be intended, but theGOTO 51is slightly misleading — it should arguably readGOTO 60. - The player’s
Yposition is fixed at 10 (line 180) and never changes, meaning the player always occupies row 10. With SCROLL moving everything upward, the effective collision row stays constant. - The score accumulation at line 270 adds the raw character code (1–63) rather than a game-meaningful point value, so different characters score wildly different amounts based purely on their ASCII codes.
- The input loop at lines 380–420 has no
GOTO 380fallback for invalid input, so entering anything other than “Y”, “N”, or “INS” silently loops back to theINPUTstatement by the implicit behaviour of the INPUT line being re-executed — but only because the interpreter re-executes line 390 after lines 400–420 all fail their conditions and execution falls off the end of the program block back to the prompt. This is effectively a hidden loop.
Content
Source Code
0 REM "CRASHER" PROGRAM CORE BY TIM HARTNELL REVISIONS, INSTRUCTION AND MOVING GRAPHIC SCREENS BY ANTHONY WILLING
3 CLS
5 LET HS=0
10 GOTO 9000
20 PRINT "%I%N%S%T%R%U%C%T%I%O%N%S%? (Y/N)"
30 INPUT U$
40 IF U$="Y" THEN GOTO 51
50 IF U$="N" THEN GOTO 155
55 IF U$="" THEN GOTO 20
60 CLS
70 PRINT AT 0,0;"%C%R%A%S%H%E%R";AT 1,0;"-------"
80 PRINT
85 PRINT
90 PRINT "YOU ARE THE ""V"". YOUR JOB--"
95 PRINT "CRASH INTO LETTERS AND NUMBERS,"
100 PRINT "WHICH SCORES POINTS."
105 PRINT
110 PRINT "YOU STEER WITH THE ""5"" AND ""8"""
115 PRINT "KEYS"
120 PRINT
125 PRINT "AVOID THE %I%N%V%E%R%S%E CHARACTERS--"
130 PRINT "THEY ARE A MUTATED LIFE FORM,"
135 PRINT "AND HITTING ONE OF THEM HEAD ON"
137 PRINT "WILL END THE GAME"
140 PRINT
141 PRINT "THE SCREEN WILL SHIFT 100 TIMES,"
142 PRINT "THEN THE GAME ENDS."
145 GOSUB 9900
147 PRINT
148 PRINT
150 GOSUB 9900
155 GOSUB 9900
156 PRINT AT 20,11;"%R%E%A%D%Y%?%?"
157 GOSUB 9900
160 CLS
170 LET X=10
180 LET Y=10
190 LET S=0
200 LET F=S
210 LET F=F+1
220 PRINT AT 20,INT (RND*20);CHR$ (INT (RND*63+1)+(128 AND RND<.2));AT Y,X;" "
230 SCROLL
240 LET X=X+(INKEY$="8" AND X<19)-(INKEY$="5" AND X>0)
250 PRINT AT Y,X;"V";AT Y+1,X;
260 LET A=PEEK (PEEK 16398+256*PEEK 16399)
270 IF A<64 THEN LET S=S+A
274 IF A>127 THEN GOSUB 2700
279 IF A>127 THEN GOTO 290
280 IF F<100 THEN GOTO 210
290 CLS
310 IF S>HS THEN LET HS=S
330 PRINT "%G%A%M%E% %O%V%E%R","%S%C%O%R%E"
340 PRINT " ",S
350 PRINT
360 PRINT "%H%I%G%H% %S%C%O%R%E ";HS
370 PRINT
380 PRINT AT 11,0;"%L%I%K%E% %A%N%O%T%H%E%R% %T%R%Y%?%? (Y/N)"
385 PRINT AT 15,0;"(%E%N%T%E%R INS %F%O%R% %I%N%S%T%R%U%C%T%I%O%N%S)"
390 INPUT U$
400 IF U$="Y" THEN GOTO 155
410 IF U$="N" THEN GOTO 2000
420 IF U$="INS" THEN GOTO 60
2000 CLS
2009 PRINT AT 11,0;"% ";AT 11,30;"% "
2010 FOR E=1 TO 15
2015 PRINT AT 11,E-1;" ";AT 11,31-E;" "
2020 PRINT AT 11,E;"% ";AT 11,30-E;"% "
2030 NEXT E
2050 FOR Q=1 TO 20
2060 FAST
2070 PRINT AT 11,14;"% % "
2080 SLOW
2090 NEXT Q
2100 PRINT AT 11,13;"% % "
2110 PRINT AT 10,13;"/ /"
2115 PRINT AT 9,14;"* *"
2120 PRINT AT 12,14;"OWW"
2125 GOSUB 9900
2130 CLS
2135 PRINT AT 11,11;"%C%R%A%S%H%E%R"
2140 GOSUB 9900
2145 PRINT AT 11,10;"%G%A%M%E% %O%V%E%R"
2150 POKE 16384,74
2699 STOP
2700 FOR Q=1 TO 20
2710 FAST
2720 SLOW
2730 NEXT Q
2735 PRINT AT 11,10;"%C%R%A%S%H"
2736 GOSUB 9900
2740 RETURN
8999 STOP
9000 PRINT AT 0,11;"%C%R%A%S%H%E%R";AT 20,11;"%C%R%A%S%H%E%R"
9010 GOSUB 9900
9020 FOR G=0 TO 9
9025 PRINT AT G-1,11;" ";AT 21-G,11;" "
9030 PRINT AT G,11;"%C%R%A%S%H%E%R";AT 20-G,11;"%C%R%A%S%H%E%R"
9045 PRINT AT 9,11;" ";AT 11,11;" "
9050 NEXT G
9060 PRINT AT 10,11;"%C%R%A%S%H%E%R"
9070 FOR Q=1 TO 20
9080 FAST
9090 SLOW
9100 NEXT Q
9110 GOSUB 9900
9115 GOSUB 9900
9120 PRINT AT 10,11;" "
9130 GOTO 11
9900 FOR P=1 TO 50
9910 NEXT P
9920 RETURN
9990 STOP
9991 CLEAR
9992 SAVE "1019%5"
9993 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
