Skip to content

Finish the session

Finish the session in a readable Sinclair BASIC opponent game.

  • Sinclair ZX Spectrum
  • BASIC

A round is complete. Now make the program welcoming to a new player and useful for several rounds: opening instructions, a small tally, alternate starters and replay that keeps the final board visible.

Replace lines 20, 30, 40, 280, 340, 650, 5000, 5010, 5020, 5030, 5040.

Add lines 50, 60, 70, 80, 90, 100, 110, 120, 130, 200, 210, 220, 1020, 1070, 1080, 5050, 5060, 5070, 5080, 5090, 5100, 5110.

Delete lines 4900, 4910, 4920, 4930, 4940.

To delete a BASIC line, enter its number on its own.

changes.bas
  20 LET wins=0: LET losses=0: LET draws=0: LET first=1
  30 PRINT AT 3,6; INK 5;"T H R E E  I N  A  R O W"
  40 PRINT AT 7,2;"You are X. The computer is O."
  50 PRINT AT 9,4;"Three in a line wins."
  60 PRINT AT 11,4;"Choose a square with 1-9."
  70 PRINT AT 13,2;"Watch why O chooses its move."
  80 PRINT AT 16,4;"R restarts. Q quits."
  90 PRINT AT 19,6; INK 5;"S starts. Q quits."
 100 GO SUB 9000
 110 LET k$=INKEY$: IF k$="" THEN GO TO 110
 120 IF k$="q" OR k$="Q" THEN GO TO 8000
 130 IF k$<>"s" AND k$<>"S" THEN GO TO 110
 200 DIM b(9): LET moves=0: LET winner=0: LET wl=0: LET a$=""
 210 GO SUB 1000
 220 IF first=2 THEN GO TO 600
 280 IF k$="r" OR k$="R" THEN GO TO 200
 340 IF winner>0 OR moves=9 THEN GO TO 5000
 650 IF winner>0 OR moves=9 THEN GO TO 5000
1020 PRINT AT 1,2; INK 7;"W ";wins;"   L ";losses;"   D ";draws
1070 IF first=1 THEN PRINT AT 19,2; INK 5;"You start this round."
1080 IF first=2 THEN PRINT AT 19,2; INK 5;"O starts this round."
5000 IF winner=1 THEN LET wins=wins+1: LET r$="YOU WIN. Three in a row."
5010 IF winner=2 THEN LET losses=losses+1: LET r$="O WINS. Three in a row."
5020 IF winner=0 THEN LET draws=draws+1: LET r$="DRAW. No line completed."
5030 IF wl>0 THEN GO SUB 6000
5040 PRINT AT 18,2; INK 6;r$;"      "
5050 PRINT AT 1,2; INK 7;"W ";wins;"   L ";losses;"   D ";draws;"  "
5060 PRINT AT 21,2;"R: next round   Q: quit      "
5070 GO SUB 9000
5080 LET k$=INKEY$: IF k$="" THEN GO TO 5080
5090 IF k$="q" OR k$="Q" THEN GO TO 8000
5100 IF k$<>"r" AND k$<>"R" THEN GO TO 5080
5110 LET first=3 -first: GO TO 200

RUN the changed program.

Complete source at this checkpoint
three.bas
  10 BORDER 0: PAPER 0: INK 7: BRIGHT 1: CLS
  20 LET wins=0: LET losses=0: LET draws=0: LET first=1
  30 PRINT AT 3,6; INK 5;"T H R E E  I N  A  R O W"
  40 PRINT AT 7,2;"You are X. The computer is O."
  50 PRINT AT 9,4;"Three in a line wins."
  60 PRINT AT 11,4;"Choose a square with 1-9."
  70 PRINT AT 13,2;"Watch why O chooses its move."
  80 PRINT AT 16,4;"R restarts. Q quits."
  90 PRINT AT 19,6; INK 5;"S starts. Q quits."
 100 GO SUB 9000
 110 LET k$=INKEY$: IF k$="" THEN GO TO 110
 120 IF k$="q" OR k$="Q" THEN GO TO 8000
 130 IF k$<>"s" AND k$<>"S" THEN GO TO 110
 200 DIM b(9): LET moves=0: LET winner=0: LET wl=0: LET a$=""
 210 GO SUB 1000
 220 IF first=2 THEN GO TO 600
 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 GO TO 200
 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: LET moves=moves+1: GO SUB 2000
 330 GO SUB 3000
 340 IF winner>0 OR moves=9 THEN GO TO 5000
 600 PRINT AT 18,2; INK 6;"O is choosing...             "
 610 GO SUB 4000
 620 LET n=mv: LET b(n)=2: LET moves=moves+1: GO SUB 2000
 630 PRINT AT 19,2; INK 5;"O chose ";mv;": ";a$;"        "
 640 GO SUB 3000
 650 IF winner>0 OR moves=9 THEN GO TO 5000
 660 PRINT AT 18,2; INK 7;"Your move: choose 1-9.        "
 670 GO TO 250
1000 CLS
1010 PRINT AT 0,8; INK 5;"THREE IN A ROW"
1020 PRINT AT 1,2; INK 7;"W ";wins;"   L ";losses;"   D ";draws
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;"Your move: choose 1-9."
1070 IF first=1 THEN PRINT AT 19,2; INK 5;"You start this round."
1080 IF first=2 THEN PRINT AT 19,2; INK 5;"O starts this round."
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
2040 IF b(n)=2 THEN GO TO 2100
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
2100 INK 7: FOR z=0 TO 1: PLOT x-6,y+10 -z: DRAW 12,0: DRAW 4,-4: DRAW 0,-12: DRAW -4,-4: DRAW -12,0: DRAW -4,4: DRAW 0,12: DRAW 4,4: NEXT z
2110 RETURN
3000 LET winner=0: LET wl=0: RESTORE 9500
3010 FOR w=1 TO 8: READ p,q,f
3020 IF b(p)<>0 AND b(p)=b(q) AND b(q)=b(f) THEN LET winner=b(p): LET wl=w
3030 NEXT w: RETURN
4000 LET mark=2: GO SUB 4500
4010 IF mv>0 THEN LET a$="win": RETURN
4020 LET mark=1: GO SUB 4500
4030 IF mv>0 THEN LET a$="block": RETURN
4040 IF b(5)=0 THEN LET mv=5: LET a$="centre": RETURN
4050 RESTORE 9530
4060 FOR j=1 TO 4: READ v
4070 IF mv=0 AND b(v)=0 THEN LET mv=v
4080 NEXT j
4090 IF mv>0 THEN LET a$="corner": RETURN
4100 FOR j=1 TO 9: IF b(j)=0 THEN LET mv=j
4110 NEXT j: LET a$="edge": RETURN
4500 LET mv=0: RESTORE 9500
4510 FOR w=1 TO 8: READ p,q,f
4520 IF mv=0 AND b(p)=mark AND b(q)=mark AND b(f)=0 THEN LET mv=f
4530 IF mv=0 AND b(p)=mark AND b(f)=mark AND b(q)=0 THEN LET mv=q
4540 IF mv=0 AND b(q)=mark AND b(f)=mark AND b(p)=0 THEN LET mv=p
4550 NEXT w: RETURN
5000 IF winner=1 THEN LET wins=wins+1: LET r$="YOU WIN. Three in a row."
5010 IF winner=2 THEN LET losses=losses+1: LET r$="O WINS. Three in a row."
5020 IF winner=0 THEN LET draws=draws+1: LET r$="DRAW. No line completed."
5030 IF wl>0 THEN GO SUB 6000
5040 PRINT AT 18,2; INK 6;r$;"      "
5050 PRINT AT 1,2; INK 7;"W ";wins;"   L ";losses;"   D ";draws;"  "
5060 PRINT AT 21,2;"R: next round   Q: quit      "
5070 GO SUB 9000
5080 LET k$=INKEY$: IF k$="" THEN GO TO 5080
5090 IF k$="q" OR k$="Q" THEN GO TO 8000
5100 IF k$<>"r" AND k$<>"R" THEN GO TO 5080
5110 LET first=3 -first: GO TO 200
6000 RESTORE 9500: FOR w=1 TO wl: READ p,q,f: NEXT w
6010 LET row=INT ((p-1)/3): LET col=p-1 -row*3
6020 LET sx=80 +col*48: LET sy=132 -row*40
6030 LET row=INT ((f-1)/3): LET col=f-1 -row*3
6040 INK 6: PLOT sx,sy: DRAW 80 +col*48 -sx,132 -row*40 -sy: 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 RETURN
9500 DATA 1,2,3,4,5,6,7,8,9
9510 DATA 1,4,7,2,5,8,3,6,9
9520 DATA 1,5,9,3,5,7
9530 DATA 1,3,7,9

RUN begins at the title. S starts, R restarts or begins the next round, and Q quits. Complete a round and press R: O should start the next one. Restart that unfinished round and O should still start it.

Two kinds of state

Line 20 creates the session values: wins, losses, draws and first. They are initialised once, before the title. Line 200 creates round state: a fresh board, zero moves, no winner, no winning line and an empty reason.

A restart now goes to 200 rather than using RUN. It preserves the session tally and first. That is why abandoning a round does not erase earlier results or change who starts. RUN remains a complete session restart.

The title has its own input loop. It waits for S or Q and releases the previous key before accepting input. When first is 2, line 220 goes straight to the computer’s move path after drawing the board. An empty board leads O to its centre preference.

Count a result once

Lines 5000–5020 increase exactly one tally and choose its message. The program then highlights a winning line, updates the display and waits at 5080. Ignored keys return to that waiting line, not to the scoring statements. Holding a key or pressing an unrelated number must never count the result twice.

R from a completed result uses 3 - first to switch the next starter, then goes to 200. R during play goes directly to 200, preserving first. Those two routes deliberately have different meanings.

The board and O’s last reason remain visible while the result waits. The game is silent: shapes, captions and the winning line provide the feedback. No timer pushes you past a position before you can read it.

Why would GO TO 10 be wrong for the R command during play?

Show the explanation

It would clear the session tally, reset the starter and return to the title. We want a fresh round while keeping the session, so the correct destination is 200.

Try Q from the title, during play and after a result. Begin again with RUN. Play the fork from a human-first round, replay with O first, and restart that round before finishing. Check both the starter caption and the tally each time.

Sources

Steven Vickers, edited by Robin Bradbeer, ZX Spectrum BASIC Programming, second edition (Sinclair Research, 1983), chapter 5, chapter 7, chapter 13, chapter 18.

Run it here

This unit's program, built for you.

Program
three.tap
Machine
ZX Spectrum 48K (PAL)

Download three.tap