Battle Ship

This file is part of and Timex Sinclair Public Domain Library Tape 1007. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 1000
Tags: Game

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 increments HITS.
  • 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:

  1. 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).
  2. Subroutines 5670 and 5700 check all required cells are still 143; if any are occupied, flag A=1 to retry.
  3. Subroutine 5640 increments the appropriate dimension (N or W) to fill consecutive cells within a FOR P loop.

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:

VariableRole
LBCount of ‘B’ (Battleship) hits this hunt
LCCount of ‘C’ (Cruiser) hits this hunt
LDCount of ‘D’ (Destroyer) hits this hunt
LZDirectional search phase (0–3: left, right, up, down)
LZDRecords which direction produced a confirmed hit
LYSub-state for two-hit continuation
LRSub-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 %3 is inverse ‘3’) saves with an auto-run flag.

Bugs and Anomalies

  • Lines 1800–1816: The conditional chain for LZ states uses direct GOTO 1970 / GOTO 1965 falls, 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 for JJ sets JJ without ever using it subsequently.
  • Line 6418: A bare RETURN with no corresponding GOSUB visible in the listing — likely a vestige of deleted code.
  • Line 6834: The ship placement input routine at 6700 reads coordinates into B$ and C/D but never actually writes the ship into M or L — 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: HITS tracks 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

Appears On

Assembled by Tim Ward from many sources. Contains programs 10294-10335.

Related Products

Related Articles

Related Content

Image Gallery

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.

People

No people associated with this content.

Scroll to Top