Ships Attack is a dodge-and-survive game in which the player moves a ship left and right along row 20 to avoid bombs falling from the top of the screen. Four bombs descend simultaneously, each tracked by parallel arrays b() and c() for row and column positions, and each rendered in a different INK color (1–4) to distinguish them visually. When 25 bombs have been successfully dodged, the variable s increments from 1 to 2, doubling the falling speed. Collision detection uses a simple arithmetic range check on the difference between bomb column c(i) and ship column v. The ship graphic is built from Spectrum block graphic characters stored in the string variable v$.
Program Analysis
Program Structure
The program is organized into a main loop and a single initialization subroutine. Line 10 displays the title screen; line 15 shows instructions and waits for a keypress using PAUSE NOT PI (equivalent to PAUSE 0). Line 20 calls the initialization subroutine at line 200, after which the main game loop runs from lines 30–170.
- Lines 10–15: Title and instructions screen.
- Lines 20–170: Main game loop — erase old positions, read input, move player, move bombs, draw bombs, check collisions.
- Lines 199–270: Initialization subroutine — sets paper color, defines graphic strings, initializes variables and arrays, seeds bomb positions from DATA.
- Line 280: DATA for initial bomb row/column positions.
Variable and Array Usage
| Variable | Purpose |
|---|---|
v | Player ship column position (starts at 13) |
v$ | Ship graphic string (block graphics) |
s$ | Bomb graphic string (block graphics) |
s | Bomb fall speed (1 normally, 2 after 25 points) |
p | Points scored (bombs that reached row 20 safely) |
b(4) | Row position of each bomb |
c(4) | Column position of each bomb |
i | Loop index for bomb processing |
Key BASIC Idioms
Player movement on line 40 uses a compact boolean arithmetic idiom common in Spectrum BASIC: LET v=v+(INKEY$="8" AND v<23)-(INKEY$="5" AND v>3). Boolean expressions evaluate to 1 (true) or 0 (false), so this single statement both increments and decrements v with built-in boundary clamping — no IF statements needed.
The wait for a keypress on line 15 uses PAUSE NOT PI. Since PI is non-zero, NOT PI evaluates to 0, making this equivalent to PAUSE 0, which pauses indefinitely until a key is pressed — a common idiomatic shorthand.
Bomb Mechanics
Each bomb is tracked as an index into the parallel arrays b() (row) and c() (column). On each pass through the loop, line 70 checks whether a bomb has reached or passed row 20. If so (lines 80–90), the bomb is recycled: reset to row 4 with a new random column near the player (v-3+INT(RND*11)), and the score increments. Otherwise (line 120), the bomb advances by s rows per frame.
The speed variable s starts at 1 and jumps to 2 at line 100 when p=25, permanently doubling the descent rate for the rest of the game.
Collision Detection
Collision is checked on line 150 only when a bomb has reached row 20 (b(i)<20 is false). The condition (c(i)-v<5 AND c(i)-v>0) tests whether the bomb column falls within a 4-column window to the right of the ship column. This is a simple but asymmetric check: it only detects hits when the bomb is 1–4 columns to the right of v, meaning bombs arriving to the left of center may not always trigger a collision as expected. On a hit, a two-second beep plays, the screen is reset, and the game restarts from line 10.
Graphics
Both the ship and bombs use Spectrum block graphic characters embedded directly in string variables. The ship string v$ (line 210) is a multi-character pattern using ▖, ▄, and ▘ block elements forming a small vessel silhouette. The bomb string s$ (line 220) uses a single ▖ block character. Each bomb is printed with INK i where i is 1–4, giving each bomb a distinct color.
Notable Anomalies
- The erase loop at line 30 prints a space at the current bomb position before movement, but since bombs move by up to 2 rows per frame at higher speed, a one-row erase may leave ghost characters on screen at speed 2.
- The collision check on line 150 is asymmetric: it only detects bombs landing 1–4 columns to the right of
v. Bombs landing atc(i)=vor to the left ofvare not flagged as hits. - The scoring increments for every bomb that passes row 20 safely (line 90), but the reset column calculation
v-3+INT(RND*11)is relative to the player’s current position, meaning bombs always respawn near the player rather than at a random screen column. - Lines 30 and 40 both call
INKEY$in separate statements within a tight loop but without any intervening pause; this means input is sampled on every iteration without buffering, which is standard but can make very fast key taps easy to miss.
Content
Source Code
10 CLS : PRINT ''TAB 10;"SHIPS ATTACK"
15 PRINT '''"USE 5 KEY TO MOVE SHIP TO LEFT AND 8 KEY TO MOVE SHIP TO RIGHT .. THIS WILL AVOID THE BOMBS AND BUILD UP YOUR SCORE."'''''"Press any key when ready": PAUSE NOT PI
20 GO SUB 200
30 FOR i=1 TO 4: PRINT AT b(i),c(i);" ";: NEXT i
40 LET v=v+(INKEY$="8" AND v<23)-(INKEY$="5" AND v>3)
50 PRINT AT 20,v; INK 6;v$;
60 FOR i=1 TO 4
70 IF b(i)<20 THEN GO TO 120
80 LET b(i)=4: LET c(i)=v-3+INT (RND*11)
90 LET p=p+1: PRINT AT 0,8;p;
100 IF p=25 THEN LET s=2
110 GO TO 130
120 LET b(i)=b(i)+s
130 PRINT AT b(i),c(i); INK i;s$;
140 IF b(i)<20 THEN GO TO 160
150 IF (c(i)-v<5 AND c(i)-v>0) THEN BEEP 2,20: INK 0: PAPER 7: CLS : GO TO 10
160 NEXT i
170 GO TO 30
199 REM init.
200 PAPER 5: CLS
210 LET v$=" \'.\..\..\.' "
220 LET s$="\.."
230 LET s=1: LET p=0: LET v=13
240 DIM b(4): DIM c(4)
250 FOR i=1 TO 4: READ b(i): READ c(i): NEXT i
260 PRINT AT 0,0;"POINTS: 0";
270 RETURN
280 DATA 16,4,12,8,4,16,8,20
9999 SAVE "S. Attack" LINE 1
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

