ZAP is a short arcade-style missile interception game where the player must manoeuvre a ground-based launcher left and right to shoot down incoming projectiles. The player’s cannon is displayed at the bottom of the screen using block graphics, and each missile descends toward it over 18 animation frames. Movement is controlled via keys 5 and 8, read with INKEY$ on every frame, and a hit is registered when the missile’s horizontal position falls within two columns of the launcher. The game runs 20 rounds and reports how many missiles were landed (missed) versus stopped (intercepted) at the end. Variable P$ is constructed as a string expression (“P”, “P+1”, or “P-1”) and then evaluated with VAL each frame to drift the missile horizontally during its descent.
Program Analysis
Program Structure
The program is compact at roughly 20 active lines. The outer FOR I=1 TO 20 loop (lines 30–140) controls the 20 missile waves. The inner FOR H=4 TO 21 loop (lines 70–130) animates a single missile descending row by row. Lines 10–20 initialise the score S and the player’s cannon column M. Line 150–170 display the final result and halt.
Missile Initialisation
At the start of each wave (lines 40–60), three variables are set:
R = INT(RND*3)— a random drift direction: 0 = left, 1 = straight, 2 = right.P— starting column, calculated as13 - (12 AND R=0) + (12 AND R=2) + INT(RND*5). WhenR=0, P starts around column 1; whenR=2, around column 25; otherwise around column 13–17. The random offset adds up to 4 columns of variation.P$— a string encoding the per-frame column update expression:"P"(straight),"P+1"(drift right), or"P-1"(drift left).
String-as-Expression Technique
Lines 60 and 80 demonstrate a notable BASIC idiom: P$ is built by string concatenation using boolean masking (AND R yields the string “+1” only when R is non-zero; AND R=2 appends “-1” only when drifting left). On each animation frame, LET P=VAL P$ re-evaluates this expression to update the missile’s column position. This avoids an explicit IF/THEN branch and keeps the inner loop tight.
Player Movement and Rendering
Inside the inner loop, line 90 reads INKEY$ twice in the same statement to update M, moving right on key 8 (clamped to column 29) and left on key 5 (clamped to column 1). Line 100 clears the screen every frame, and line 110 draws three elements with a single PRINT AT statement:
- The cannon at row 21 using block graphics
\.:\:.(▄█▄ appearance). - The missile at row
Husing block graphics\.'\'.\(▖▘▖ appearance). - A bullet/exhaust marker
*at row24-H(rising as the missile falls, creating a visual trail).
Hit Detection
Line 120 checks for a hit when the missile reaches row 12 (mid-screen): H=12 AND M>P-2 AND M<P+2, giving a ±1 column tolerance window. On a hit, execution jumps to line 180, which increments S and prints a small explosion pattern using TAB positioning before returning to the outer loop via GOTO 140. Misses simply complete the inner loop and fall through to NEXT I.
Scoring and Display
The final screen (lines 150–160) reports two figures: 20-S missiles landed (missed) and S missiles stopped (intercepted). The use of PRINT "LANDED:";20-S means the comma after 20-S advances to the next print zone before displaying “STOPPED:”.
Key Variables Summary
| Variable | Role |
|---|---|
S | Interception (hit) counter |
M | Cannon column position (1–29) |
I | Wave counter (1–20) |
R | Drift direction (0=left, 1=straight, 2=right) |
P | Missile column position (updated each frame) |
P$ | String expression for P update (“P”, “P+1”, or “P-1”) |
H | Missile row (4–21, animation frame counter) |
Potential Issues
- The screen is cleared (
CLS) on every frame inside the inner loop, which causes significant flicker since there is no double-buffering available. - Hit detection only triggers at
H=12(mid-screen), not at the cannon’s actual row 21, so missiles that are nearly on top of the cannon but slightly off-centre will never be intercepted even if they visually pass through it. P$is constructed in line 60 as"P"+("+1" AND R)+("-1" AND R=2). WhenR=2, bothAND RandAND R=2are true, soP$becomes"P+1-1", which evaluates correctly toP— makingR=2effectively a straight trajectory, not a left drift. Left drift ("P-1") can never actually occur, meaning only straight and rightward-drifting missiles appear.
Content
Source Code
5 REM "ZAP"
10 LET S=0
20 LET M=14
30 FOR I=1 TO 20
40 LET R=INT (RND*3)
50 LET P=13-(12 AND R=0)+(12 AND R=2)+INT (RND*5)
60 LET P$="P"+("+1" AND R)+("-1" AND R=2)
70 FOR H=4 TO 21
80 LET P=VAL P$
90 LET M=M+(INKEY$="8" AND M<29)-(INKEY$="5" AND M>1)
100 CLS
110 PRINT AT 21,M-1;"\.:\:.";AT H,P-1;"\.'\'.";AT 24-H,M;"*"
120 IF H=12 AND M>P-2 AND M<P+2 THEN GOTO 180
130 NEXT H
140 NEXT I
150 CLS
160 PRINT "LANDED:";20-5,"STOPPED:";S
170 STOP
180 LET S=S+1
190 PRINT AT H-1,P;"*";TAB P-1;"***";TAB P;"*"
200 GOTO 140
210 SAVE "1022%8"
220 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
