Tick Tack Toe is a two-player tic-tac-toe game where players enter their names, choose X or O, and take turns pressing number keys 1–9 corresponding to grid positions. The board is drawn using PLOT commands to render two horizontal and two vertical lines forming the grid, with cell positions mapped to a 3×3 string array `E$`. Win detection is handled in a single long conditional at line 470 that checks all eight possible winning combinations, using the sentinel value 9999 in variable `W` to signal a win. The program tracks cumulative scores for X wins, O wins, and “cat” (draw) outcomes across multiple games. An animated title sequence uses random TAB positions, colored PAPER attributes, and block graphic characters to fill the screen before play begins.
Program Analysis
Program Structure
The program is organized into a main game loop and several subroutines. Execution flows through an intro sequence, player name entry, board setup, turn-by-turn play, win/draw detection, and score display, with optional replay handling at the end of each round.
| Line(s) | Purpose |
|---|---|
| 5–7 | REM header and tape-stop splash screen |
| 10 | Calls intro animation subroutines and CLEAR |
| 20–48 | Player name input, score variable initialization |
| 50–130 | Draw board using PLOT, play title tune |
| 140–175 | Initialize E$ grid array and set current player to X |
| 180–510 | Main game loop: display board, read keypresses, update grid, check for win |
| 520–610 | Win/draw announcement, score update, replay prompt |
| 1000–1070 | Subroutine: random-position colored title animation |
| 1080–1130 | Subroutine: block-graphic scrolling title effect |
| 1140–1170 | Subroutine: “Touch C to continue” splash |
| 2000–2050 | Subroutine: scrolling “ERROR TRY AGAIN” message |
| 2500–2550 | Subroutine: display current scores for X, O, and Cat |
| 3000–3040 | Replay handler: same players or restart with new names |
Board Representation
The 3×3 grid is stored in the two-dimensional string array E$(3,3), initialized with the digit characters "1" through "9" at lines 150–170. When a player claims a cell, its character is replaced with "X" or "O". A cell is considered unoccupied as long as it still holds its original digit, which also serves as the key mapping for input. The board is rendered by printing individual E$ elements at fixed AT positions rather than using a loop, making cell placement explicit but verbose.
Input Handling
The game uses a busy-wait INKEY$ polling loop at line 270. The raw key code is converted to a cell number via CODE INKEY$-48 at line 280, exploiting the fact that ASCII digit codes start at 48. Each cell is then validated by a pair of lines: one that redirects to the error subroutine if the cell is already taken, and one that assigns the current player’s mark if it is free (lines 290–460). This pattern is repeated nine times, once per cell, making the input section lengthy but straightforward.
Win Detection
All eight winning combinations — three rows, three columns, and two diagonals — are evaluated in a single IF statement at line 470 joined by OR. Note that line 470 redundantly includes both a check for the third row (E$(3,1)=A$ AND E$(3,2)=A$ AND E$(3,3)=A$) as part of the rows group and again as an explicit condition, giving nine conditions where eight are sufficient. When a win is detected, the sentinel W=9999 is set; lines 200–210 then branch to the appropriate winner announcement based on the current value of A$.
Draw (Cat) Detection
A move counter L is incremented at line 480 each turn. At line 180, after the board is displayed, the condition IF L=9 AND W<>9999 routes to line 560 for a “WINNER CAT” announcement, correctly triggering only when all nine cells are filled and no winner has been declared.
Score Tracking
Three variables maintain cumulative scores across games: G (X wins), O (O wins), and N (cat/draw). These are initialized at line 45 and incremented at lines 520, 540, and 560 respectively. The subroutine at line 2500 prints all three scores in a fixed column on the right side of the screen. Notably, L, W, and A$ are reset at lines 48 and 175 at the start of each round rather than at initialization, so scores persist correctly through replays.
Intro Animation Subroutines
The subroutine at line 1000 uses nested loops over paper colors (P 1–7) and repetition count (L 1–3) to print the title at a random TAB position, with a BEEP pitched to the random column value for a randomized audio effect. The subroutine at line 1080 prints the title surrounded by block graphic left-half characters (\: = ▌) in each of the seven paper colors, creating a colored stripe effect across the screen.
Error Message Scrolling
When an invalid cell is chosen, the subroutine at line 2000 implements a simple text ticker. It stores the message in B$, then uses a FOR loop printing a substring B$(I TO Z) that advances one character per iteration, with a BEEP pitched to the loop index. The upper bound Z is clamped to LEN B$ to avoid out-of-range errors.
Notable Bugs and Anomalies
- Line 610 has a logically impossible guard:
IF INKEY$<>"Y" OR INKEY$<>"y" OR INKEY$<>"N" OR INKEY$<>"n"is always true because any single character must differ from at least one of those four. The same pattern appears at lines 1170 and 3040. In practice this condition never filters anything meaningful, but control still reaches these lines only for unrecognized keys, so behavior is acceptable. - Line 470’s win check contains a duplicate third-row condition, giving nine OR clauses instead of eight. This is harmless but redundant.
- The variable
Ois used both as the O-win score counter (line 45) and as a loop variable name conflict risk; however, since no loop usesOas its loop variable, no actual collision occurs. - Line 10 calls
POKE 23692,22, a system variable poke specific to the ZX Spectrum/TS2068 that controls the number of lines before a scroll prompt — it has no effect on the TS1000 target mentioned in the REM. This is consistent with the July 1984 modification note for the TS2068. - The variable
Sis computed from player name lengths at lines 40 and 45, then modified at line 600, but is never read for any game logic purpose visible in the listing.
Content
Source Code
5 REM TICK TACK TOE \* Written by S.J.Weinberg 1983 For TS1000 MOD. Jul. 1984 For TS2068
7 BORDER 7: PAPER 7: CLS : PRINT AT 10,9; PAPER 2; INK 7; FLASH 1;"STOP THE TAPE"; FLASH 0: PAUSE 300
10 GO SUB 1000: POKE 23692,22: GO SUB 1080: CLEAR : GO SUB 1140
20 CLS
30 PRINT AT 1,10; INK 1;"TICK TACK TOE"'' INK 2;" \* By S.J.(BUTCH) Weinberg 7/84": BORDER 6
40 PRINT AT 6,3; INK 3;"Who will be X ?": INPUT M$ : PRINT TAB 10;M$: LET S=331: BEEP .5,1: BEEP .5,9: BEEP .5,5: BEEP .5,9
45 PRINT AT 10,3; INK 3;"Who will be O ?": INPUT N$: PRINT TAB 10;N$: LET S=S+30: BEEP .5,1: BEEP .5,9: BEEP .5,5: BEEP .5,9: LET G=0: LET O=0: LET N=0: PAUSE 100
47 CLS
48 LET W=0: LET L=0
50 PRINT AT 1,10; INK 1; FLASH 1;"TICK TACK TOE"; FLASH 0
60 FOR X=100 TO 160
70 PLOT X,84: PLOT X,85: PLOT X,98: PLOT X,99: NEXT X
110 FOR Y=70 TO 114
120 PLOT 118,Y: PLOT 119,Y: PLOT 141,Y: PLOT 142,Y: NEXT Y
130 PRINT AT 1,10; PAPER 1; INK 7;"TICK TACK TOE": BEEP .05,6: BEEP .05,6: BEEP .05,6: BEEP .05,4: BEEP .05,4: BEEP .05,4: BEEP .05,2: BEEP .05,2: BEEP .05,2
140 DIM E$(3,3)
150 LET E$(1)="123"
160 LET E$(2)="456"
170 LET E$(3)="789"
175 LET A$="X"
180 PRINT AT 8,13;E$(1,1);AT 8,16;E$(1,2);AT 8,19;E$(1,3);AT 10,13;E$(2,1);AT 10,16;E$(2,2);AT 10,19;E$(2,3);AT 12,13;E$(3,1);AT 12,16;E$(3,2);AT 12,19;E$(3,3): BEEP .05,4: BEEP .05,0: GO SUB 2500: IF L=9 AND W<>9999 THEN GO TO 560
190 PRINT AT 3,12;" "
200 IF W=9999 AND A$="O" THEN GO TO 520
210 IF W=9999 AND A$="X" THEN GO TO 540
220 IF A$="X" THEN PRINT AT 3,4; INK 4;"PLAYER X "; INK 0;M$
230 IF A$="O" THEN PRINT AT 3,4; INK 4;"PLAYER O "; INK 0;N$
235 GO TO 270
250 GO SUB 2000
270 IF INKEY$="" THEN GO TO 270
280 LET C=CODE INKEY$-48
290 IF C=1 AND E$(1,1)<>"1" THEN GO TO 250
300 IF C=1 AND E$(1,1)="1" THEN LET E$(1,1)=A$
310 IF C=2 AND E$(1,2)<>"2" THEN GO TO 250
320 IF C=2 AND E$(1,2)="2" THEN LET E$(1,2)=A$
330 IF C=3 AND E$(1,3)<>"3" THEN GO TO 250
340 IF C=3 AND E$(1,3)="3" THEN LET E$(1,3)=A$
350 IF C=4 AND E$(2,1)<>"4" THEN GO TO 250
360 IF C=4 AND E$(2,1)="4" THEN LET E$(2,1)=A$
370 IF C=5 AND E$(2,2)<>"5" THEN GO TO 250
380 IF C=5 AND E$(2,2)="5" THEN LET E$(2,2)=A$
390 IF C=6 AND E$(2,3)<>"6" THEN GO TO 250
400 IF C=6 AND E$(2,3)="6" THEN LET E$(2,3)=A$
410 IF C=7 AND E$(3,1)<>"7" THEN GO TO 250
420 IF C=7 AND E$(3,1)="7" THEN LET E$(3,1)=A$
430 IF C=8 AND E$(3,2)<>"8" THEN GO TO 250
440 IF C=8 AND E$(3,2)="8" THEN LET E$(3,2)=A$
450 IF C=9 AND E$(3,3)<>"9" THEN GO TO 250
460 IF C=9 AND E$(3,3)="9" THEN LET E$(3,3)=A$
470 IF E$(1,1)=A$ AND E$(1,2)=A$ AND E$(1,3)=A$ OR E$(2,1)=A$ AND E$(2,2)=A$ AND E$(2,3)=A$ OR E$(3,1)=A$ AND E$(3,2)=A$ AND E$(3,3)=A$ OR E$(1,1)=A$ AND E$(2,1)=A$ AND E$(3,1)=A$ OR E$(1,2)=A$ AND E$(2,2)=A$ AND E$(3,2)=A$ OR E$(1,3)=A$ AND E$(2,3)=A$ AND E$(3,3)=A$ OR E$(3,1)=A$ AND E$(3,2)=A$ AND E$(3,3)=A$ OR E$(1,1)=A$ AND E$(2,2)=A$ AND E$(3,3)=A$ OR E$(1,3)=A$ AND E$(2,2)=A$ AND E$(3,1)=A$ THEN LET W=9999
480 LET L=L+1
490 IF A$<>"X" THEN GO TO 175
500 LET A$="O"
510 GO TO 180
520 PRINT AT 18,5; INK 5; FLASH 1;"WINNER X ";M$; FLASH 0: BEEP .2,10: BEEP .2,10: BEEP .2,10: BEEP 2,-10: LET G=G+1: GO SUB 2500
530 GO TO 570
540 PRINT AT 18,5; INK 5; FLASH 1;"WINNER O ";N$; FLASH 0: BEEP .2,10: BEEP .2,10: BEEP .2,10: BEEP 2,-10: LET O=O+1: GO SUB 2500
550 GO TO 570
560 PRINT AT 18,5; INK 5; FLASH 1;"WINNER CAT "; FLASH 0;: BEEP 1,-30: BEEP 2,-50: LET N=N+1: GO SUB 2500
570 PRINT AT 19,1;"Try again? (Y or N)"
580 IF INKEY$="" THEN GO TO 580
590 IF INKEY$="Y" OR INKEY$="y" THEN PAUSE 10: GO TO 3000
600 IF INKEY$="N" OR INKEY$="n" THEN LET S=S-4881: PRINT AT 5,6; INK 2;"\* By (BUTCH) 7/84": BEEP .20,17: BEEP .20,17: BEEP .20,17: BEEP .15,5: BEEP .20,14: BEEP .20,10: BORDER 7: STOP
610 IF INKEY$<>"Y" OR INKEY$<>"y" OR INKEY$<>"N" OR INKEY$<>"n" THEN GO TO 580
1000 CLS
1010 FOR L=1 TO 3
1020 FOR P=1 TO 7
1030 LET J=INT 19*RND
1040 PRINT TAB J; PAPER P; INK 9;"TICK TACK TOE": BEEP .25,J
1050 NEXT P
1060 NEXT L
1070 RETURN
1080 FOR L=1 TO 3
1090 FOR P=1 TO 7
1100 PRINT PAPER P; INK 9;"\: \: \: \: \: \: \: \: \: TICK TACK TOE\: \: \: \: \: \: \: \: \: ": BEEP .05,P*L
1110 NEXT P
1120 NEXT L
1130 RETURN
1140 BORDER 6: PRINT INK 2; FLASH 1;AT 11,9;"TICK TACK TOE"; FLASH 0,,,: PRINT TAB 5; INK 4; FLASH 1;"Touch C to continue!!"; FLASH 0
1150 IF INKEY$="" THEN GO TO 1150
1160 IF INKEY$="C" OR INKEY$="c" THEN RETURN
1170 IF INKEY$<>"C" OR INKEY$<>"c" THEN GO TO 1150
2000 LET B$=" ERROR TRY AGAIN "
2010 LET P=LEN B$
2020 FOR I=1 TO P
2025 LET Z=I+29: IF Z>=P THEN LET Z=P
2030 PRINT AT 5,0; INK 2;" ";B$(I TO Z);" ": BEEP .05,I
2040 NEXT I
2050 RETURN
2500 PRINT AT 14,20; INK 4;"SCORES";AT 15,20;"X= ";G;AT 16,20;"O= ";O;AT 17,20;"CAT= ";N
2550 RETURN
3000 PRINT AT 20,1; INK 2;"Same players? (Y or N)"
3010 IF INKEY$="" THEN GO TO 3010
3020 IF INKEY$="Y" OR INKEY$="y" THEN GO TO 47
3030 IF INKEY$="N" OR INKEY$="n" THEN RUN 20
3040 IF INKEY$<>"Y" OR INKEY$<>"y" OR INKEY$<>"N" OR INKEY$<>"n" THEN GO TO 3010
9997 STOP
9998 SAVE "TIC TAC TO" LINE 1
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

