This program implements a torpedo-firing game where a submarine sprite moves across the screen and the player fires torpedoes by pressing keys numbered 1–5, each corresponding to a different firing angle calculated via the TAN function. The submarine is represented using a string of ZX81 block graphics stored in A$, and collision detection compares the torpedo’s Y position (derived from the tangent trajectory) against the submarine’s screen column. A high-score table tracking the best player name and score persists across rounds within the same session, resetting only on a full restart. The game limits each round to 20 combined movement/fire events (variable T) before displaying the score as a percentage of hits to total shots.
Program Analysis
Program Structure
The program is organised into a main loop, two subroutines, and an end-of-round section:
- Lines 1–15: Initialisation — clear screen, reset variables, ask for player name, prime turn counter
T=-1. - Lines 20–90: Main game loop — reset score display, call submarine movement subroutine (
GOSUB 100), then call key/fire subroutine (GOSUB 200), repeat. - Lines 100–160: Submarine movement — decrements column
Cby a random fraction, wraps back to line 30 when the sub reaches the left edge, draws the submarine sprite and a sea-floor dotted line. - Lines 200–290: Input and torpedo trajectory — reads a keypress, validates it, computes a TAN-based trajectory, plots/unplots the torpedo path, calls collision detection.
- Lines 300–399: Collision detection — checks whether the torpedo Y-coordinate at a given X matches the submarine’s position.
- Lines 400–470: Hit animation — flashes the submarine position with alternating block-graphic patterns in a loop, then animates the sub sinking downward before returning to line 30.
- Lines 500–560: End-of-round scoring — displays hits and percentage score, updates high score if beaten, pauses, clears, and loops back for the next player.
- Lines 9998–9999:
SAVEthe program (with inverse-O in the filename as a cosmetic touch) andGOTO 0to restart the system after saving.
Submarine Sprite
The submarine graphic is stored in A$ at line 5 as a string of ZX81 block graphics and spaces. The string contains hull, conning tower, and wake characters, printed at row 5 using PRINT AT 5,C;A$. The dotted line at row 7 represents the sea floor or water surface and is redrawn each movement step.
Torpedo Trajectory Calculation
Lines 200–280 implement the firing mechanic. The player presses a key whose CODE falls between 31 and 36 (ZX81 internal codes for keys 1–5 shifted). The angle is computed as:
M = TAN((10 * VAL B$) * 2 * PI / 360)
This converts VAL B$ (1–5) multiplied by 10 into degrees (10°, 20°, 30°, 40°, 50°) and takes the tangent, giving the slope of the torpedo’s path. The torpedo is then plotted and immediately unplotted (PLOT/UNPLOT at lines 250–260) as it steps across X from 1 to 63, creating a moving dot effect. Firing is also gated by C$=B$ (line 210) to prevent the same key being used twice consecutively.
Collision Detection
The subroutine at lines 300–320 computes the torpedo’s integer Y position (A = INT(INT(M*X)+0.5)) and the submarine’s integer column position (B = INT(INT(C*2)+0.5)). A hit is registered if A is 32 or 33 (the vertical screen rows corresponding to the submarine) and B is within ±2 columns of X. The use of double INT(...+0.5) is an unconventional rounding idiom — the inner INT is redundant since the argument is already the result of arithmetic, making the outer INT(...+0.5) a standard rounding-to-nearest.
Turn Limit and Scoring
The variable T counts turns and is incremented at line 35 (each movement step) and line 215 (each fire event). When T >= 20, the game ends and jumps to line 500. The final score is displayed as a percentage: INT(100*S/T), rewarding accuracy over volume of fire. The high score (HS) and high-score holder’s name (N$) persist in memory across rounds within the same session.
Hit Animation
Lines 400–420 loop 10 times, printing alternating pairs of block-graphic patterns at the submarine’s position to simulate an explosion flash. Eight distinct AT clauses appear within a single PRINT statement at line 410. Lines 440–460 then animate the sub sinking by printing a fragment at successive rows while clearing the previous row, stepping from row 5 down to row 21.
Key Validation
Line 210 checks three conditions with OR: the key code must be ≥ 31, ≤ 36, and not equal to the previously pressed key (C$ = B$). Because all three are combined with OR, the logic is: if the code is out of range or it is a repeat press, do nothing. This effectively blocks both invalid keys and repeated use of the same angle in consecutive moves, adding a tactical element.
Notable Techniques and Anomalies
- Starting
Tat-1(line 15) rather than 0 compensates for theT=T+1at line 35 executing before the first meaningful turn. - The
SAVE "TORPED%O"at line 9998 uses the ZX81 inverse-video escape%Oto render the final letter of “TORPEDO” in inverse video in the filename. GOTO 9999/GOTO 0at the end triggers a system restart after saving, a common ZX81 idiom.- The
PLOT/UNPLOTpair (lines 250–260) in the torpedo loop creates a single moving pixel without leaving a trail, using the ZX81’s pixel commands rather than character-cell printing. - The check
CODE B$ < 31 OR CODE B$ > 36uses ZX81 internal character codes, where digit keys 1–5 have codes 29–33 in some ROM versions; the exact range used here may be platform-specific and worth verifying against the target hardware’s key code table.
Content
Source Code
1 CLS
2 LET C$=""
3 LET HS=0
5 LET A$="): ..:!!. -"
10 PRINT ,,"CURRENT PLAYER 'S NAME?"
12 INPUT F$
13 PRINT AT 1,0;F$;" IS NOW PLAYING. "
15 LET T=-1
20 LET S=0
30 PRINT AT 5,2;" "
35 LET T=T+1
36 IF T>=20 THEN GOTO 500
40 LET C=28
50 GOSUB 100
60 GOSUB 200
90 GOTO 50
100 LET C=C-RND
110 IF C<2 THEN GOTO 30
120 PRINT AT 5,C;A$
130 PRINT AT 7,0;". . . . . . . . . . . . . . . ."
160 RETURN
200 LET B$=INKEY$
210 IF CODE B$<31 OR CODE B$>36 OR C$=B$ THEN RETURN
212 LET C$=B$
215 LET T=T+1
216 IF T>=20 THEN GOTO 500
220 LET M=(TAN ((10*VAL B$)*2*PI/360))
230 FOR X=1 TO 63 STEP 2
240 IF M*X>43 THEN RETURN
250 PLOT X,M*X
260 UNPLOT X,M*X
270 GOSUB 300
280 NEXT X
290 RETURN
300 LET A=INT (INT (M*X)+.5)
310 LET B=INT (INT (C*2)+.5)
320 IF (A=32 OR A=33) AND (B>=X-2) AND (B<=X+1) THEN GOTO 400
399 RETURN
400 FOR N=1 TO 10
410 PRINT AT 5,C-1;"@@##@@##";AT 6,C-1;"##@@##@@";AT 5,C-1;"!!!!!!!!";AT 6,C-1;";;;;;;;;";AT 5,C-1;";;;;;;;;";AT 6,C-1;"!!!!!!!!";AT 5,C-1;"~~~~~~~~";AT 6,C-1;",,,,,,,,";AT 5,C-1;" ";AT 6,C-1;" "
420 NEXT N
430 LET S=S+1
440 FOR N=5 TO 21
450 PRINT AT N,C-1;",,;;,,,,";AT N-1,C-1;" "
460 NEXT N
470 GOTO 30
500 PRINT AT 21,0;S;" SUBS TORPEDOED - SCORE = ";INT (100*S/T)
510 IF S<=HS THEN GOTO 540
520 LET N$=F$
530 LET HS=S
540 PRINT AT 19,0;N$;" - HIGH SCORE - ";HS
550 PAUSE 200
560 CLS
600 GOTO 10
9998 SAVE "TORPED%O"
9999 GOTO 0
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
