Make the numbered squares respond to a key. This is a drawing experiment: every legal choice places X, and we have not added winning or turns yet.
Replace lines 40.
Add lines 250, 260, 270, 280, 290, 300, 310, 320, 330, 1060, 1090, 2050, 2060, 8000, 9000, 9010.
40 GO TO 250
250 GO SUB 9000
260 LET k$=INKEY$: IF k$="" THEN GO TO 260
270 IF k$="q" OR k$="Q" THEN GO TO 8000
280 IF k$="r" OR k$="R" THEN RUN
290 IF k$<"1" OR k$>"9" THEN GO TO 250
300 LET n=VAL k$
310 IF b(n)<>0 THEN PRINT AT 18,2; INK 6;"Taken. Choose an empty square.": GO TO 250
320 LET b(n)=1: GO SUB 2000
330 GO TO 250
1060 PRINT AT 18,2; INK 7;"Choose a square with 1-9."
1090 PRINT AT 21,2; INK 7;"1-9: place R: reset Q: quit"
2050 INK 5: FOR z=0 TO 1: PLOT x-10 +z,y-10: DRAW 20,20: PLOT x-10 +z,y+10: DRAW 20,-20: NEXT z
2060 RETURN
8000 PAPER 0: INK 7: BRIGHT 0: PRINT AT 21,2;"Three in a Row finished. ": STOP
9000 IF INKEY$<>"" THEN GO TO 9000
9010 RETURNRUN the changed program.
Complete source at this checkpoint
10 BORDER 0: PAPER 0: INK 7: BRIGHT 1: CLS
20 DIM b(9)
30 GO SUB 1000
40 GO TO 250
250 GO SUB 9000
260 LET k$=INKEY$: IF k$="" THEN GO TO 260
270 IF k$="q" OR k$="Q" THEN GO TO 8000
280 IF k$="r" OR k$="R" THEN RUN
290 IF k$<"1" OR k$>"9" THEN GO TO 250
300 LET n=VAL k$
310 IF b(n)<>0 THEN PRINT AT 18,2; INK 6;"Taken. Choose an empty square.": GO TO 250
320 LET b(n)=1: GO SUB 2000
330 GO TO 250
1000 CLS
1010 PRINT AT 0,8; INK 5;"THREE IN A ROW"
1030 INK 1: FOR i=0 TO 3: PLOT 56 +i*48,32: DRAW 0,120: NEXT i
1040 FOR i=0 TO 3: PLOT 56,32 +i*40: DRAW 144,0: NEXT i
1050 FOR n=1 TO 9: GO SUB 2000: NEXT n
1060 PRINT AT 18,2; INK 7;"Choose a square with 1-9."
1090 PRINT AT 21,2; INK 7;"1-9: place R: reset Q: quit"
1100 RETURN
2000 LET row=INT ((n-1)/3): LET col=n-1 -row*3
2010 LET x=80 +col*48: LET y=132 -row*40
2020 PRINT AT 5 +row*5,10 +col*6; INK 7;" "
2030 IF b(n)=0 THEN PRINT AT 5 +row*5,10 +col*6; INK 7;n: RETURN
2050 INK 5: FOR z=0 TO 1: PLOT x-10 +z,y-10: DRAW 20,20: PLOT x-10 +z,y+10: DRAW 20,-20: NEXT z
2060 RETURN
8000 PAPER 0: INK 7: BRIGHT 0: PRINT AT 21,2;"Three in a Row finished. ": STOP
9000 IF INKEY$<>"" THEN GO TO 9000
9010 RETURNRUN the program and press 5. A cyan cross replaces the centre number. Press 5 again: the program says that the square is taken. Try a letter, then another empty square. Only a valid empty square should change.
Accept a move before drawing it
INKEY$ supplies a character while a key is pressed, or an empty string when none is pressed. The $ identifies a string variable. Line 260 keeps looking until k$ contains something. Q quits and R runs the program again, clearing the array and board.
The comparison on line 290 rejects characters outside "1" to "9". Only then does VAL convert the character to a number. This order keeps unrelated keys away from both VAL and the array subscript.
Line 310 tests b(n). <> means “not equal to”. An occupied square sends us back to the input loop before anything changes. A legal move stores 1, then calls the same cell routine used for the initial numbers. This time b(n) is nonzero, so the routine continues into the cross drawing.
An IF condition that fails skips the rest of that BASIC line. The RETURN after printing an empty square therefore belongs to the empty-square case; it does not prevent a cross being drawn.
Give one press one action
The routine at 9000 waits while INKEY$ is nonempty. It returns once the player releases the key. Calling it before the next input prevents a held key from being treated as a succession of moves. Hold 1 down to try it, then release and press a different number.
Two diagonals form X. Their ends lie ten pixels either side of the centre. A loop with z equal to 0 and 1 draws each diagonal twice, one pixel apart, making the mark substantial enough to read. The cell routine removes the old number with a space first.
Would drawing the cross be enough to make a square occupied?
Show the explanation
No. Legality comes from b(n). Without LET b(n)=1, another press would still find zero. The drawing displays the decision; it does not store it.
Fill all nine squares. This checkpoint keeps accepting input even when all squares are taken. R clears it; Q stops it. Both behaviours are deliberate while we develop the rules.
Keyboard notes
For INKEY$, enter extended mode, then press N; for VAL use extended mode, then J. Symbol Shift with W enters <>. The release loop uses the empty string: two quotation marks with nothing between them.
Sources
Steven Vickers, edited by Robin Bradbeer, ZX Spectrum BASIC Programming, second edition (Sinclair Research, 1983), chapter 9, chapter 13, chapter 17, chapter 18.
Run it here
This unit's program, built for you.
- Program
- three.tap
- Machine
- ZX Spectrum 48K (PAL)