Skip to content

Remember the clues

Store the search in a two-dimensional array.

  • Sinclair ZX Spectrum
  • BASIC

The target needs two numbers, but our search can reveal information at 64 different positions. An array gives those positions a common name and a pair of indices.

A small array experiment

First enter Q to leave the game. Save this version with SAVE "sonarwork", record the tape output using your emulator’s save workflow, and check that you can load it. Keep that saved program before entering NEW for this separate experiment.

Add lines 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110.

step-01-edits.bas
  10 DIM g(8,8)
  20 PRINT g(1,1)
  30 FOR r=1 TO 8
  40 FOR c=1 TO 8
  50 LET g(r,c)=-1
  60 NEXT c
  70 NEXT r
  80 PRINT g(1,1);" ";g(8,8)
  90 LET g(1,2)=3
 100 PRINT g(1,2);" ";g(2,1)
 110 STOP
Complete program for this step
step-01.bas
  10 DIM g(8,8)
  20 PRINT g(1,1)
  30 FOR r=1 TO 8
  40 FOR c=1 TO 8
  50 LET g(r,c)=-1
  60 NEXT c
  70 NEXT r
  80 PRINT g(1,1);" ";g(8,8)
  90 LET g(1,2)=3
 100 PRINT g(1,2);" ";g(2,1)
 110 STOP

DIM g(8,8) creates a numeric array with eight rows and eight columns. g(1,2) names one element: row 1, column 2. It is different from g(2,1). Sinclair numeric array names, like FOR loop variables, use a single letter.

DIM fills the elements with zero. The first PRINT demonstrates that. Our game already uses zero for a hit, so we need a different value for an unknown cell. The nested loops set every element to -1. This special value is called a sentinel: its meaning comes from our program’s rules.

The last assignment puts code 3 in g(1,2) as an experiment, not as a measured probe. The output is 0, then -1 -1, then 3 -1 on separate lines. Changing one element does not change the element with the indices reversed.

Bring memory into the game

Reload the saved banded game from the preceding lesson. Apply these edits to that game, not to the array experiment.

Delete lines 60, 70, 120, 130, 140, 170, 171, 172, 173, 180, 190, 195, 230, 250, 251, 252, 270, 1140, 1180, 4000, 4030, 4040, 4050, 4070, 4080. Enter each line number on its own, then press Enter.

Replace lines 10, 80, 160, 200, 210, 220, 240, 260, 1130, 3015, 3100, 9000.

Add lines 25, 26, 27, 28, 150, 151, 152, 153, 261, 262, 280, 290, 310, 1190, 2100, 2110, 2120, 2130, 2140, 2145, 2150, 2160, 2170, 2180, 2190, 2600, 2610, 2620, 2630.

step-02-edits.bas
  10 LET stage=6
  25 DIM g(8,8)
  26 FOR r=1 TO 8: FOR c=1 TO 8: LET g(r,c)=-1: NEXT c: NEXT r
  27 LET lr=0: LET lc=0: LET pr=0: LET pc=0
  28 LET d=0: LET v=0: LET a$="": LET b$="": LET p$=""
  80 LET s$="N=1-2, M=3-4, F=5+ steps.": GO SUB 2600
 150 LET d=ABS (pr-tr)+ABS (pc-tc)
 151 IF d>4 THEN LET d=3: GO TO 160
 152 IF d>2 THEN LET d=2: GO TO 160
 153 IF d>0 THEN LET d=1
 160 LET g(pr,pc)=d
 200 LET oldr=lr: LET oldc=lc: LET lr=pr: LET lc=pc
 210 IF oldr=0 THEN GO TO 240
 220 LET r=oldr: LET c=oldc: GO SUB 2100
 240 LET r=pr: LET c=pc: GO SUB 2100
 260 LET s$="Far: at least 5 steps away."
 261 IF d=2 THEN LET s$="Medium: 3 or 4 steps away."
 262 IF d=1 THEN LET s$="Near: 1 or 2 steps away."
 280 IF d=0 THEN LET s$="Found! Q quits; RUN tries again"
 290 GO SUB 2600
 310 GO TO 100
1130 GO SUB 2100
1190 RETURN
2100 GO SUB 2000
2110 LET z=g(r,c): LET b$=". "
2120 IF z=-1 THEN GO TO 2160
2130 LET b$=" F"
2140 IF z=2 THEN LET b$=" M"
2145 IF z=1 THEN LET b$=" N"
2150 IF z=0 THEN LET b$=" *"
2160 LET m$=" "
2170 IF r=lr AND c=lc THEN LET m$=">"
2180 PRINT AT y,x;m$;b$;AT y+1,x;"   "
2190 RETURN
2600 PAPER 0: INK 7
2610 PRINT AT 21,0;"                               ";
2620 PRINT AT 21,0;s$;
2630 RETURN
3015 IF LEN a$>16 THEN GO SUB 1000
3100 LET s$="Use one digit from 1 to 8.": GO SUB 2600
9000 LET s$="Finished. RUN to try again.": GO SUB 2600
Complete program for this step
step-02.bas
  10 LET stage=6
  20 LET tr=3: LET tc=6
  25 DIM g(8,8)
  26 FOR r=1 TO 8: FOR c=1 TO 8: LET g(r,c)=-1: NEXT c: NEXT r
  27 LET lr=0: LET lc=0: LET pr=0: LET pc=0
  28 LET d=0: LET v=0: LET a$="": LET b$="": LET p$=""
  30 GO SUB 1000
  80 LET s$="N=1-2, M=3-4, F=5+ steps.": GO SUB 2600
 100 LET p$="Row": GO SUB 3000: LET pr=v
 110 LET p$="Column": GO SUB 3000: LET pc=v
 150 LET d=ABS (pr-tr)+ABS (pc-tc)
 151 IF d>4 THEN LET d=3: GO TO 160
 152 IF d>2 THEN LET d=2: GO TO 160
 153 IF d>0 THEN LET d=1
 160 LET g(pr,pc)=d
 200 LET oldr=lr: LET oldc=lc: LET lr=pr: LET lc=pc
 210 IF oldr=0 THEN GO TO 240
 220 LET r=oldr: LET c=oldc: GO SUB 2100
 240 LET r=pr: LET c=pc: GO SUB 2100
 260 LET s$="Far: at least 5 steps away."
 261 IF d=2 THEN LET s$="Medium: 3 or 4 steps away."
 262 IF d=1 THEN LET s$="Near: 1 or 2 steps away."
 280 IF d=0 THEN LET s$="Found! Q quits; RUN tries again"
 290 GO SUB 2600
 310 GO TO 100
1000 BORDER 1: PAPER 0: INK 7: CLS
1010 PRINT AT 0,6;"SONAR N1-2 M3-4 F5+"
1020 FOR c=1 TO 8
1030 PRINT AT 2,6 +3 *(c-1);c
1040 NEXT c
1050 PRINT AT 3,4;"+------------------------+"
1060 PRINT AT 20,4;"+------------------------+"
1070 FOR r=1 TO 8
1080 PRINT AT 4 +2 *(r-1),2;r
1090 FOR k=0 TO 1
1100 PRINT AT 4 +2 *(r-1)+k,4;":";AT 4 +2 *(r-1)+k,29;":"
1110 NEXT k
1120 FOR c=1 TO 8
1130 GO SUB 2100
1150 NEXT c
1160 PAPER 0: INK 7
1170 NEXT r
1190 RETURN
2000 LET y=4 +2 *(r-1): LET x=5 +3 *(c-1)
2010 PAPER 1: INK 7
2020 IF r+c=2 *INT ((r+c)/2) THEN PAPER 5: INK 0
2030 RETURN
2100 GO SUB 2000
2110 LET z=g(r,c): LET b$=". "
2120 IF z=-1 THEN GO TO 2160
2130 LET b$=" F"
2140 IF z=2 THEN LET b$=" M"
2145 IF z=1 THEN LET b$=" N"
2150 IF z=0 THEN LET b$=" *"
2160 LET m$=" "
2170 IF r=lr AND c=lc THEN LET m$=">"
2180 PRINT AT y,x;m$;b$;AT y+1,x;"   "
2190 RETURN
2600 PAPER 0: INK 7
2610 PRINT AT 21,0;"                               ";
2620 PRINT AT 21,0;s$;
2630 RETURN
3000 PAPER 0: INK 7
3010 INPUT (p$+" (1-8, Q): "); LINE a$
3015 IF LEN a$>16 THEN GO SUB 1000
3020 IF a$="q" OR a$="Q" THEN GO TO 9000
3030 IF LEN a$<>1 THEN GO TO 3100
3040 IF a$<"1" OR a$>"8" THEN GO TO 3100
3050 LET v=VAL a$
3060 RETURN
3100 LET s$="Use one digit from 1 to 8.": GO SUB 2600
3110 GO TO 3010
9000 LET s$="Finished. RUN to try again.": GO SUB 2600
9010 STOP

At the start, lines 25–26 create and initialise the array. A valid probe still calculates its distance and band, then line 160 stores that code in g(pr,pc). The target stays in tr and tc. The array contains the player’s knowledge, not a secret marker waiting to be read.

We now draw through the cell routine at 2100. It calls 2000 to get the position and paper colour, reads g(r,c) into z, and chooses the printed clue. A value of -1 leaves the dot. Codes 1, 2 and 3 select N, M and F; zero selects the asterisk. m$ is a space except at the latest probe, where it becomes >.

The main loop saves the previous marker coordinates in oldr and oldc, then makes the new probe the latest position. Redrawing the old cell removes its marker but keeps its stored clue. Redrawing the new cell adds the marker there. The full-board routine calls the same cell routine for every square, so recovery after a long input answer also restores the search.

The status routine at 2600 clears and prints the message held in s$. This moves repeated message work into one place. The renderer reads clues; it never calculates a distance or changes the target.

Why would using zero for unknown cells make the board misleading?

Show the explanation

Zero already means that a probe found the target. A fresh array of zeros would therefore look like a board full of discoveries. Initialising to -1 gives unknown cells their own meaning.

Probe (1,2) and (8,8). Both should show F, with the marker only on the second. Return to (1,2): both clues remain and the marker moves back. This version recalculates repeated probes; next we will recognise them before doing any new search work.

Sources

Steven Vickers, edited by Robin Bradbeer, ZX Spectrum BASIC Programming, second edition (Sinclair Research, 1983), chapters 4 and 12 (nested loops and numeric arrays).

Run it here

This unit's program, built for you.

Program
step-02.tap
Machine
ZX Spectrum 48K (PAL)

Download step-02.tap