This is a two-player Battleships game where one side is the human and the other is a computer opponent. The program maintains two 10×10 grids: array M for the computer’s ships and array L for the player’s ocean, both initialised via nested FOR loops in the subroutine at line 5000. Ships are represented by their ASCII character codes — ‘B’ (66) for Battleship, ‘C’ (67) for Cruiser, and ‘D’ (68) for Destroyer — and hit detection compares cell values against 143 (the ZX81 checkerboard graphic used as an empty-sea marker). The computer AI uses a set of state variables (LB, LC, LD, LZ, LZD, LR, LY) to track ship-type hits and navigate a search pattern with directional logic spread across subroutines from line 1800 to 2442. Ship placement for both sides uses random orientation (AA=0 for N/S, AA=1 for E/W) with collision checking before committing coordinates.
Program Analysis
Program Structure
The program is organised into clearly separated functional blocks accessed via GOSUB:
- Lines 10–150: Initialisation, display setup, and coin-toss to determine who moves first.
- Lines 700–790: Human move handler — parses alphanumeric grid input, looks up the computer’s grid array
M, and incrementsHITS. - Lines 1000–1080: Computer move dispatcher — routes to placement or AI search subroutines based on state variables.
- Lines 1500–1995: Computer ship-hunting AI — random placement (1500), miss-state assignment (1550/1580), and directional search logic (1800–1990).
- Lines 2000–2442: Extended AI continuation — follow-up movement after confirming a hit direction.
- Lines 4000–4072: End-game: win/loss messages, replay prompt.
- Lines 5000–5136: Array and variable initialisation.
- Lines 5300–5534: Grid display and computer fleet placement.
- Lines 5600–5720: Random ship placement helper subroutines.
- Lines 6500–6850: Human fleet placement and SAVE.
Grid Representation
Two separate arrays encode the two oceans. Array M(10,10) holds the computer’s ship grid; array L(16,16) holds the player’s grid with guard borders. Both use a sentinel value of 143 (the ZX81 checkerboard block graphic character) to denote empty sea, and ASCII codes 66 (‘B’), 67 (‘C’), 68 (‘D’) for ship types. The value 46 (ASCII ‘.’) is used in L for the human’s playable ocean cells, while 100 fills the border guard zones to prevent the AI from wandering out of bounds.
Hit detection in the human’s turn (line 750) checks M(N,W)<>143; any non-empty cell is counted as a hit. The displayed character at line 770 is CHR$ J where J=M(N,W). Lines 772 and 1061–1064 apply a crude inverse-video convention: if J>100 the value is reduced by 100 before display, suggesting ship values may be stored offset by 100 to flag a “hit” state, though this logic is inconsistently implemented.
Ship Placement
The computer’s fleet is placed by subroutines starting at line 5400. Three ship types are placed: one Battleship (4 cells), two Cruisers (3 cells), three Destroyers (2 cells). Placement works as follows:
- Subroutine 5600 selects a random orientation (
AA=0 for N/S, 1 for E/W) and a random start coordinate bounded by the ship length (AB). - Subroutines 5670 and 5700 check all required cells are still 143; if any are occupied, flag
A=1to retry. - Subroutine 5640 increments the appropriate dimension (
NorW) to fill consecutive cells within aFOR Ploop.
The human places ships interactively via lines 6500–6834 using directional prompts (N/S or E/W) and an alphanumeric grid square input (e.g. “A3”).
Input Parsing
Both human-move input (line 710) and ship-placement input (line 6750) parse a two-character string. The column letter is converted with CODE B$-64 (moves, line 720) or CODE B$-65 (placement, line 6770), giving a 1-based or 0-based column index respectively — a minor inconsistency between the two grids’ coordinate systems. The row is extracted with VAL A$(2).
Computer AI
The AI uses a set of state variables rather than a proper search stack:
| Variable | Role |
|---|---|
LB | Count of ‘B’ (Battleship) hits this hunt |
LC | Count of ‘C’ (Cruiser) hits this hunt |
LD | Count of ‘D’ (Destroyer) hits this hunt |
LZ | Directional search phase (0–3: left, right, up, down) |
LZD | Records which direction produced a confirmed hit |
LY | Sub-state for two-hit continuation |
LR | Sub-state for three-hit continuation |
After a first hit (LB=1, LC=1, or LD=1), the AI at line 1800 begins probing adjacent cells in sequence. Once a direction is confirmed (LZD set), subroutines at 2000+ continue moving in that direction. Reset conditions in subroutines 1650–1790 clear state variables when a ship’s full length is reached (e.g. LB=4 resets LB, LY, LR, and LZ at line 1770–1780).
Notable Techniques and Idioms
- The coin-toss at lines 135–150 uses
INT(RND*2)to pick who goes first. - Line 1033 uses
NOT M$="H" AND NOT M$="M"as an input validation loop — standard ZX81 BASIC idiom. - The grid display at line 5300 prints both grids side by side in a single loop using a fixed-width format string with embedded spaces.
- The
SAVE "1033%3"at line 6850 (where%3is inverse ‘3’) saves with an auto-run flag.
Bugs and Anomalies
- Lines 1800–1816: The conditional chain for
LZstates uses directGOTO 1970/GOTO 1965falls, but lines 1810–1816 are never reached because line 1804 unconditionally jumps to 1970, bypassing 1810 entirely. The AI’s directional logic after line 1800 is therefore incomplete. - Line 1063:
PRINT "%1"attempts to print inverse ‘1’ as a flag before placing a character on the player’s grid, but the logic at 1061–1064 forJJsetsJJwithout ever using it subsequently. - Line 6418: A bare
RETURNwith no correspondingGOSUBvisible in the listing — likely a vestige of deleted code. - Line 6834: The ship placement input routine at 6700 reads coordinates into
B$andC/Dbut never actually writes the ship intoMorL— the loop at 6500–6596 calls 6700 repeatedly but only the display and input are handled; placement into the array is absent from the human-side routine. - Line 750 vs 780:
HITStracks human hits on the computer’s grid and triggers the win at 16 (a full 4+3+3+2+2+2=16 cell total), but the counter at line 750 increments for any non-143 cell including already-hit cells, allowing double-counting on repeated shots.
Content
Source Code
10 FAST
50 GOSUB 6000
100 GOSUB 5000
110 CLS
115 GOSUB 5300
117 SLOW
120 GOSUB 6500
130 GOSUB 5400
135 LET Z=INT (RND*2)
137 IF Z=1 THEN GOTO 150
140 GOTO 700
150 GOTO 1000
700 PRINT AT 14,14;"YOUR MOVE"
710 INPUT D$
715 LET B$=D$(1)
717 LET C=VAL D$(2)
720 LET D=CODE B$-64
730 LET W=D
733 LET N=C+1
740 LET J=M(N,W)
750 IF M(N,W)<>143 THEN LET HITS=HITS+1
770 PRINT AT C,D;CHR$ J
772 IF J>100 THEN LET J=J-100
780 IF HITS=16 THEN GOTO 4000
790 GOTO 150
1000 IF LB=0 AND LD=0 THEN GOSUB 1500
1010 IF LB=1 OR LC=1 OR LD=1 THEN GOSUB 1800
1020 IF LB>1 OR LC>1 THEN GOSUB 2000
1030 INPUT M$
1033 IF NOT M$="H" AND NOT M$="M" THEN GOTO 1030
1040 IF M$="M" THEN GOSUB 1550
1050 IF M$="H" THEN GOSUB 1580
1060 PRINT AT X-4,Y+9;CHR$ J
1061 IF J>100 THEN LET JJ=J-100
1062 IF J<100 THEN LET JJ=J
1063 PRINT "%1";AT X+7,Y-3;CHR$ J
1064 IF J>100 THEN PRINT "%0";AT X+7,Y-3;CHR$ J
1065 LET L(X,Y)=J
1070 IF HATS=16 THEN GOTO 4020
1080 GOTO 140
1500 LET X=INT (RND*10)+4
1502 LET Y=INT (RND*10)+4
1510 IF L(X,Y)<>46 THEN GOTO 1500
1515 IF L(X+1,Y)<>46 AND L(X,Y-1)<>46 AND L(X-1,Y)<>46 AND L(X,Y+1)<>46 THEN GOTO 1500
1520 LET YA=Y+61
1530 PRINT AT 14,14;"MY TURN";YA;X-4
1535 PRINT AT X+7,Y-3;"?"
1540 RETURN
1550 LET J=143
1560 IF LB=1 OR LC=1 OR LD=1 THEN LET LZ=LZ+1
1570 RETURN
1580 PRINT AT 16,14;"B,C OR D?"
1590 INPUT N$
1591 FOR N=1 TO 9
1592 PRINT AT 16,N+13;CHR$ 32
1593 NEXT N
1600 LET HATS=HATS+1
1610 IF N$="B" THEN GOSUB 1750
1620 IF N$="C" THEN GOSUB 1700
1630 IF N$="D" THEN GOSUB 1650
1640 RETURN
1650 LET J=CODE "D"
1660 LET LD=LD+1
1670 IF LD=2 THEN LET LZ=0
1680 IF LD=2 THEN LET LD=0
1690 RETURN
1700 LET J=CODE "C"
1710 LET LC=LC+1
1720 IF LC=3 THEN LET LZ=0
1722 LET LY=0
1730 IF LC=3 THEN LET LC=0
1740 RETURN
1750 LET J=CODE "B"
1760 LET LB=LB+1
1770 IF LB=4 THEN LET LZ=0
1772 LET LY=0
1774 LET LR=0
1780 IF LB=4 THEN LET LB=0
1790 RETURN
1800 IF (LB=1 OR LC=1) AND LZ=0 THEN IF (L(X-2,Y)<>46 AND L(X+1,Y)<>46) OR (L(X-1,Y)<>46 AND L(X+2,Y)<>46) THEN LET Y=Y-1
1802 LET LZ=2
1804 GOTO 1970
1810 IF (LB=1 OR LC=1) AND LZ=1 THEN IF L(X+3,Y)<>46 THEN LET X=X+1
1812 LET Y=Y-1
1814 LET LZ=2
1816 GOTO 1970
1850 IF LZ=0 THEN GOTO 1890
1860 IF LZ=1 THEN GOTO 1930
1870 IF LZ=2 THEN GOTO 1965
1880 IF LZ=3 THEN GOTO 1985
1890 LET X=X-1
1900 IF L(X,Y)<>46 THEN GOTO 1920
1910 LET LZD=1
1912 GOTO 1990
1920 LET LZ=LZ+1
1930 LET X=X+2
1940 IF L(X,Y)<>46 THEN GOTO 1960
1950 LET LZD=2
1952 GOTO 1990
1960 LET LZ=LZ+1
1965 LET X=X-1
1966 LET Y=Y-1
1970 IF L(X,Y)<>46 THEN GOTO 1980
1975 LET LZD=3
1976 GOTO 1990
1980 LET LZ=LZ+1
1985 LET Y=Y+2
1986 LET LZD=4
1990 GOSUB 1520
1995 RETURN
2000 IF LZD=1 THEN GOSUB 2050
2010 IF LZD=2 THEN LET X=X+1
2020 IF LZD=3 THEN GOSUB 2080
2030 IF LZD=4 THEN LET Y=Y+1
2040 GOSUB 1520
2042 RETURN
2050 IF LB=2 OR LC=2 THEN GOSUB 2110
2060 IF LB=3 THEN GOSUB 2300
2070 RETURN
2080 IF LB=2 OR LC=2 THEN GOSUB 2160
2090 IF LB=3 THEN GOTO 2400
2100 RETURN
2110 IF (LB=2 OR LC=2) AND LY=1 THEN LET X=X+3
2112 RETURN
2120 LET X=X-1
2130 IF X=3 THEN GOTO 2150
2140 IF L(X,Y)=46 THEN LET LY=LY+1
2142 RETURN
2150 IF LB=2 OR LC=2 THEN LET X=X+3
2152 RETURN
2160 IF (LB=2 OR LC=2) AND LY=1 THEN LET Y=Y+3
2162 RETURN
2170 LET Y=Y-1
2180 IF Y=3 THEN GOTO 2200
2190 IF L(X,Y)=46 THEN LET LY=LY+1
2192 RETURN
2200 IF LB=2 OR LC=2 THEN LET Y=Y+3
2202 RETURN
2300 IF LR=1 THEN LET X=X+4
2302 RETURN
2310 LET X=X-1
2320 IF X=3 THEN LET X=X+4
2322 RETURN
2330 IF L(X,Y)<>46 THEN LET X=X+2
2332 RETURN
2340 IF L(X,Y)=46 THEN LET LR=1
2342 RETURN
2400 IF LR=1 THEN LET Y=Y+4
2402 RETURN
2410 LET Y=Y-1
2420 IF Y=3 THEN LET Y=Y+4
2422 RETURN
2430 IF L(X,Y)<>46 THEN LET Y=Y+2
2432 RETURN
2440 IF L(X,Y)=46 THEN LET LR=1
2442 RETURN
4000 PRINT AT 16,14;"YOU WON"
4002 GOTO 4040
4020 PRINT AT 16,14;" I WON "
4022 GOTO 4040
4040 PRINT AT 16,14;"AGAIN? (Y/N)"
4050 INPUT Y$
4055 IF NOT Y$="Y" THEN GOTO 4070
4060 IF Y$="Y" THEN RUN
4070 PRINT AT 21,14;"OK BYE"
4072 STOP
5000 DIM L(16,16)
5025 DIM M(10,10)
5026 FOR N=1 TO 10
5027 FOR W=1 TO 10
5028 LET M(N,W)=143
5030 NEXT W
5032 NEXT N
5035 RAND
5040 LET HITS=0
5042 LET HATS=0
5050 LET LB=0
5052 LET LC=0
5054 LET LD=0
5056 LET LZ=0
5058 LET LA=0
5060 LET LZD=0
5070 LET LX=0
5072 LET LY=0
5074 LET XX=0
5076 LET LR=0
5080 FOR X=1 TO 3
5082 FOR Y=1 TO 3
5090 LET L(X,Y)=100
5092 NEXT Y
5094 NEXT X
5100 FOR X=4 TO 13
5102 FOR Y=4 TO 13
5110 LET L(X,Y)=46
5112 NEXT Y
5114 NEXT X
5120 FOR X=14 TO 16
5122 FOR Y=14 TO 16
5130 LET L(X,Y)=100
5132 NEXT Y
5134 NEXT X
5136 RETURN
5300 FOR A=0 TO 9
5310 PRINT A;".......... ..........";A
5320 NEXT A
5330 PRINT " ABCDEFGHIJ ABCDEFGHIJ "
5350 FOR A=0 TO 9
5360 PRINT A;".........."
5362 NEXT A
5400 LET AB=6
5402 GOSUB 5600
5404 FOR P=1 TO 4
5420 LET M(N,W)=CODE "B"
5430 GOSUB 5640
5432 NEXT P
5440 FOR E=1 TO 2
5450 LET AB=7
5452 GOSUB 5600
5454 GOSUB 5670
5456 IF A=1 THEN GOTO 5450
5460 FOR P=1 TO 3
5470 LET M(N,W)=CODE "C"
5480 GOSUB 5640
5482 NEXT P
5484 NEXT E
5490 FOR E=1 TO 3
5500 LET AB=8
5502 GOSUB 5600
5504 GOSUB 5700
5506 IF A=1 THEN GOTO 5500
5510 FOR P=1 TO 2
5520 LET M(N,W)=CODE "D"
5530 GOSUB 5640
5532 NEXT P
5534 NEXT E
5540 RETURN
5600 LET A=0
5602 LET AA=INT (RND*2)
5610 IF AA=0 THEN LET N=INT (RND*AB)+1
5612 LET W=INT (RND*10)+1
5620 IF AA=1 THEN LET N=INT (RND*10)+1
5622 LET W=INT (RND*AB)+1
5630 RETURN
5640 IF AA=0 THEN LET N=W+1
5650 IF AA=1 THEN LET W=W+1
5660 RETURN
5670 IF AA=0 THEN IF M(N,W)<>143 OR M(N+1,W)<>143 OR M(N+2,W)<>143 THEN LET A=1
5680 IF AA=1 THEN IF M(N,W)<>143 OR M(N,W+1)<>143 OR M(N,W+2)<>143 THEN LET A=1
5700 IF AA=0 THEN IF M(N,W)<>143 OR M(N+1,W)<>143 THEN LET A=1
5710 IF AA=1 THEN IF M(N,W)<>143 OR M(N,W+1)<>143 THEN LET A=1
5720 RETURN
6418 RETURN
6500 LET X$="BATTLESHIP (4)"
6520 LET DF=6
6522 LET J=66
6530 LET X=4
6532 GOSUB 6700
6540 LET X$="CRUISER (3)"
6550 LET DF=7
6552 LET J=67
6554 LET X=3
6560 GOSUB 6700
6562 GOSUB 6700
6570 LET X$="DESTROYER (2)"
6580 LET DF=8
6582 LET J=68
6584 LET X=2
6590 GOSUB 6700
6592 GOSUB 6700
6594 GOSUB 6700
6596 RETURN
6600 PRINT AT 14,17;" ";AT 15,15;" ";AT 16,15;" ";AT 17,18;" ";AT 18,13;" "
6610 RETURN
6630 IF BR=1 THEN LET C=C+1
6640 IF BR=2 THEN LET D=D+1
6650 RETURN
6700 PRINT AT 14,17;"INPUT";AT 15,15;"1 FOR N/S";AT 16,15;"2 FOR E/W"
6710 INPUT BR
6712 IF BR<1 OR BR>2 THEN GOTO 6710
6720 IF BR=1 THEN LET DD=DF
6722 LET DE=9
6730 IF BR=2 THEN LET DD=9
6732 LET DE=DF
6740 PRINT AT 14,17;"ENTER";AT 15,15;"STARTING ";AT 16,15;" SQUARE ";AT 17,18;"FOR";AT 18,13;X$
6750 INPUT A$
6760 LET B$=A$(1)
6762 LET C=VAL A$(2)
6770 LET D=CODE B$-65
6800 GOSUB 6600
6834 RETURN
6840 CLEAR
6850 SAVE "1033%3"
6860 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
