--- title: "3D Tic Tac Toe" id: 53785 type: "computer_media" slug: "3dtictactoe" url: "http://localhost/computer_media/3dtictactoe/" markdown_url: "http://localhost/computer_media/3dtictactoe.md" published_at: "2024-05-13T18:56:52+00:00" modified_at: "2026-03-30T21:40:52+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A fully strategic 3D tic-tac-toe game on a 3×3×3 grid, with three AI difficulty levels and all 49 possible winning lines tracked simultaneously." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_contents: - id: 53877 title: "SINCUS Exchange Tape 101 – Entertainment" type: "computer_media" url: "http://localhost/computer_media/sincus-exchange-tape-101-entertainment/" - id: 55430 title: "Timex Sinclair Public Domain Library Tape 2004" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-2004/" - id: 64711 title: "Long Island Sinclair Timex (LIST) User Group Library Tape #2.2" type: "computer_media" url: "http://localhost/computer_media/long-island-sinclair-timex-list-user-group-library-tape-2-2/" media_type: "Program" images: - url: "http://localhost/wp-content/uploads/2024/05/3d-tic-tac-toe-2.png" - url: "http://localhost/wp-content/uploads/2024/05/3d-tic-tac-toe-1.png" media_type_tags: "Game" --- # 3D Tic Tac Toe This program implements a three-dimensional tic-tac-toe game on a 3×3×3 grid, offering 49 possible winning lines across horizontal, vertical, and diagonal orientations in all three spatial dimensions. Two custom UDG characters (at positions 144 and 145) are defined via POKE USR to render the player and computer tokens on the board. The computer AI operates at three skill levels: level 1 uses random moves, level 2 skips blocking and winning checks, and level 3 plays a full strategic sequence — center first, then blocking human threats, then seeking its own winning moves. Game state is tracked using two arrays: `a(27)` stores piece placement and `b(49)` records the sum of each of the 49 lines, allowing win detection by checking for sums of 3 (computer) or 12 (human, using value 4). The board is rendered with PLOT/DRAW commands to create an isometric-style 3D visual effect with three labeled levels (A, B, C). *** ## Program Analysis ### Program Structure The program is organized into clearly delineated sections separated by REM statements. Execution begins at line 1 but immediately jumps to subroutine `9900` for the instructions and skill-level selection screen. After returning, the board is initialized and drawn before entering the main game loop. 1. **Lines 1–95:** Setup — UDG definition, array initialization, screen configuration 2. **Lines 100–175:** Board drawing using `PRINT AT` and `PLOT`/`DRAW` 3. **Lines 185–350:** Human move input and validation 4. **Lines 1000–2055:** Computer AI move selection 5. **Lines 7000–7030:** Random fallback move 6. **Lines 7500–7800:** Gap-finding subroutine for line completion 7. **Lines 8000–8830:** Move display, line state recording, win/draw detection, turn switching 8. **Lines 9000–9480:** End-of-game scoring and replay prompt 9. **Lines 9500–9540:** Reusable `INKEY$` keypress subroutine 10. **Lines 9600–9640:** Line state storage subroutine 11. **Lines 9900–9995:** Instructions screen and level selection ### Data Representation The 3×3×3 grid is flattened into a one-dimensional array `a(27)`, where positions 1–9 are level A (bottom), 10–18 are level B (middle), and 19–27 are level C (top). Cell values use `1` for the computer and `4` for the human, chosen deliberately so that line sums are unambiguous: a sum of `3` in `b(f)` means the computer owns all three cells in that line, while a sum of `12` means the human does. The array `b(49)` stores the running sum of all 49 lines and is updated via the `GO SUB 9600` subroutine each time a move is made. ### UDG Character Definition Two UDG characters are defined at startup using a `FOR` loop (lines 20–50) with `POKE USR CHR$ g+f, a`. UDG \a (char 144) holds the computer’s token and \b (char 145) the human’s token, based on the 8-byte bitmaps in the DATA statements at lines 60–70. These are rendered on the board at line 8080 using the expression `("\a" AND m=1)+("\b" AND m=0)`, a compact Boolean string-selection idiom common in Sinclair BASIC. ### AI Strategy and Skill Levels The computer’s move logic (lines 1000–2055) implements a priority-ordered strategy that is curtailed at lower skill levels: - **Level 1:** Only takes center (position 14) if empty; otherwise picks randomly (line 7000). - **Level 2:** Takes center, then tries to create its own two-in-a-row, then falls back to strategic positions. - **Level 3:** Full strategy — center, block human’s winning threats, create computer winning threats, strategic corners/faces, then random. The DATA blocks at lines 1060–1080 list the 49 line indices in a priority order. The subroutine at line 7500 receives a line index `t` and uses a chain of conditional `FOR` loops to locate the empty cell in that line, storing it in `a` (repurposed as a temporary variable). ### 49-Line Enumeration The win-check section (lines 8500–8745) iterates over all 49 lines using multiple `FOR` loops that call `GO SUB 9600` to accumulate sums into `b()`. The line categories covered are: | Line Type | Count | Lines | | --- | --- | --- | | Vertical columns (through levels) | 9 | 8510–8525 | | Horizontal rows within levels (one axis) | 9 | 8530–8555 | | Horizontal rows within levels (other axis) | 9 | 8560–8575 | | Level-spanning face diagonals | 3+3+3+3 | 8580–8695 | | Space diagonals (corner to corner) | 4 | 8710–8745 | ### Board Rendering The 3D board is drawn in two passes. First, `PRINT AT` statements (lines 105–140) place the digit characters 1–9 as position labels within each of the three levels, using `CHR$ a` with `a` starting at 49 (ASCII “1”). Then `PLOT`/`DRAW` commands (lines 145–170) draw isometric lines to visually suggest the three-dimensional stacked layers. The `POKE 23658,8` at line 95 enables `CAPS LOCK` for uppercase input throughout the game. ### Move Coordinate Mapping The conversion from a flat position index `posn` to screen coordinates is performed in lines 8030–8070. The level offset is computed first, then the row and column within the level are derived using modular arithmetic. This mapping must account for the staggered isometric offsets applied during board drawing. ### Notable Techniques and Idioms - **Boolean arithmetic strings:**`("\a" AND m=1)+("\b" AND m=0)` selects between two single-character strings without an `IF` statement. - **Plural suffix:**`"line"+("s" AND b<>1)` correctly pluralizes the score message. - **INKEY$ handshake:** The subroutine at 9500 first waits for any held key to be released (line 9510), then waits for a new keypress (9520), preventing repeated key detection. - **RESTORE targeting:**`RESTORE 1060` and `RESTORE 2055` rewind the DATA pointer to specific lines, allowing the same DATA blocks to be re-read multiple times during AI processing. - **Variable reuse:**`a` and `b` are heavily reused as loop variables, counters, and temporary values in addition to being array names `a()` and `b()`; Sinclair BASIC permits scalar and array variables to share a name. - **GO SUB via variable:**`LET a=9600` followed by `GO SUB a` at lines 8505–8520 uses a variable as the subroutine target, allowing the same dispatch loop to call the line-recording routine without repeating the literal line number. ### Potential Anomalies The gap-finding subroutine at lines 7510–7620 uses a chain of `IF ... FOR` constructs without explicit `ELSE` branching — all conditions are evaluated sequentially. This is safe only because the ranges of `t` are mutually exclusive. However, if `t` falls outside all defined ranges (e.g., due to unexpected DATA), no `FOR` loop is opened and the subsequent `NEXT p` at line 7800 would cause an error. The DATA priority list at lines 1060–1080 contains exactly 49 values matching the `b(49)` array, so in normal play this situation should not arise. At line 8830, the expression `1000-(800 AND m)` evaluates to `200` when `m=1` (human’s turn) and `1000` when `m=0` (computer’s turn), providing a single-line branch to alternate turns without an explicit `IF` statement. ## Source Code ``` 1 REM 3d tic-tac-toe 5 GO SUB 9900 10 REM define characters 20 FOR g=144 TO 145: FOR f=0 TO 7 30 READ a 40 POKE USR CHR$ g+f,a 50 NEXT f: NEXT g 60 DATA 0,120,132,130,65,33,30,0 70 DATA 0,136,72,56,24,20,18,17 80 REM initialise 85 DIM a(27): DIM b(49): LET go=0 90 BORDER 1: PAPER 1: INK 4: CLS 95 POKE 23658,8: POKE 23659,1 100 REM print board 105 FOR f=1 TO 15 STEP 7 110 LET b=8: LET a=49 115 FOR p=f TO f+5 STEP 2 120 FOR q=b TO b+9 STEP 4 125 PRINT AT p,q; INK 5;CHR$ a 130 LET a=a+1: NEXT q 135 LET b=b+2 140 NEXT p: NEXT f 145 FOR f=14 TO 127 STEP 56 150 PLOT 122,f: DRAW -44,44 155 PLOT 154,f: DRAW -44,44 160 PLOT 80,f+14: DRAW 84,0 165 PLOT 64,f+30: DRAW 84,0 170 NEXT f 175 INK 6: PRINT AT 0,0;"LEVEL";AT 3,2;"A";AT 10,2;"B";AT 17,2;"C" 180 REM decide who goes first 185 PRINT AT 22,2;"Do you want to go first?": BEEP .05,40 190 GO SUB 9500 192 IF a$<>"Y" AND a$<>"N" THEN BEEP .1,-24: GO TO 190 194 PRINT AT 22,2,, 196 IF a$="N" THEN LET m=0: GO TO 1000 198 LET m=1 200 REM human's move 210 PRINT AT 0,25;"Your";AT 2,25;"move?" 220 PRINT AT 8,25;"Press";AT 10,25;"level";AT 12,24;"(A,B,C)" 230 PRINT AT 16,25;"then";AT 18,25;"number";AT 20,24;"(1 - 9)" 235 BEEP .05,40 240 GO SUB 9500 245 IF a$<>"A" AND a$<>"B" AND a$<>"C" THEN BEEP .1,-24: GO TO 240 250 BEEP .08,31 260 LET a=CODE a$-64 270 PRINT AT 22,0;"YOUR MOVE IS ";a$;"- ";: PRINT AT 22,15; 280 GO SUB 9500 290 IF a$<"1" OR a$>"9" THEN BEEP .1,-24: PRINT "? Start again.": GO TO 240 300 PRINT a$: BEEP .1,31 310 LET posn=VAL a$+(9 AND a=2)+(18 AND a=3) 320 IF a(posn)<>0 THEN BEEP .1,-24: PRINT AT 22,0;"That place is full: try again.": GO TO 240 330 LET a(posn)=4 340 FOR p=0 TO 21 STEP 2: PRINT AT p,24;" ": NEXT p 350 GO TO 8000 1000 REM computer's move 1005 PRINT AT 22,0;"I'M THINKING...";: BEEP .005,12 1010 REM is center filled? 1020 IF a(14)=0 THEN LET a(14)=1: LET posn=14: GO TO 8000 1025 PRINT ".";: BEEP .005,12 1030 IF level=1 THEN GO TO 7000 1050 REM check for 2 in a row 1060 DATA 14,23,5,48,46,49,47,33,28,39,36,45,43,40,37,30,31,34,42 1070 DATA 25,1,12,9,10,19,7,3,18,21,27,16,35,44,32,29,41,38 1080 DATA 11,20,15,17,2,8,4,26,22,6,13,24 1100 REM -first, human's lines 1105 IF level=2 THEN GO TO 1180 1110 RESTORE 1060 1115 FOR f=1 TO 49 1120 READ t 1125 IF b(t)=8 THEN GO TO 7500 1130 NEXT f 1135 PRINT ".";: BEEP .005,12 1140 REM then, computer's lines 1145 RESTORE 1060 1150 FOR f=1 TO 49 1155 READ t 1160 IF b(t)=2 THEN GO TO 7500 1170 NEXT f 1175 PRINT ".";: BEEP .005,12 1180 REM can computer line 2 up? 1185 RESTORE 1060 1190 FOR f=1 TO 49 1195 READ t 2000 IF b(t)=1 THEN GO TO 7500 2005 NEXT f 2010 PRINT ".";: BEEP .005,12 2015 REM If not, look for empty faces and corners 2020 RESTORE 2055 2025 FOR f=1 TO 14 2030 READ t 2035 IF a(t)=0 THEN LET posn=t: LET a(t)=1: GO TO 8000 2040 NEXT f 2050 PRINT ".";: BEEP .005,12 2055 DATA 15,23,5,13,23,11,27,19,3,7,1,21,25,9 7000 REM if none, random move 7010 LET posn=INT (RND*27)+1 7020 IF a(posn)=0 THEN LET a(posn)=1: GO TO 8000 7030 BEEP .005,12: GO TO 7000 7500 REM Find gap in line 7505 LET a=0 7510 IF t<10 THEN FOR p=t TO t+18 STEP 9 7515 IF t>9 AND t<19 THEN LET q=((t-9) AND t<13)+((t-3) AND (t<16 AND t>12))+((t+3) AND t>15): FOR p=q TO q+7 STEP 3 7520 IF t>18 AND t<28 THEN LET q=(t-19)*3+1: FOR p=q TO q+2 7530 IF t>27 AND t<31 THEN LET q=t-27: FOR p=q TO q+24 STEP 12 7540 IF t>30 AND t<34 THEN LET q=(t-31)*3+1: FOR p=q TO q+20 STEP 10 7550 IF t>33 AND t<37 THEN LET q=t-27: FOR p=q TO q+12 STEP 6 7560 IF t>36 AND t<40 THEN LET q=(t-37)*3+3: FOR p=q TO q+16 STEP 8 7570 IF t>39 AND t<43 THEN LET q=(t-40)*9+1: FOR p=q TO q+8 STEP 4 7580 IF t>42 AND t<46 THEN LET q=(t-43)*9+3: FOR p=q TO q+4 STEP 2 7590 IF t=46 THEN FOR p=1 TO 27 STEP 13 7600 IF t=47 THEN FOR p=3 TO 25 STEP 11 7610 IF t=48 THEN FOR p=7 TO 21 STEP 7 7620 IF t=49 THEN FOR p=9 TO 19 STEP 5 7800 LET a=a+(p AND (a=0 AND a(p)=0)): NEXT p 7900 REM record computer's move 7910 LET posn=a: LET a(a)=1 8000 REM print move 8010 IF m=0 THEN PRINT " ";CHR$ (CODE "B"-(1 AND posn<10)+(1 AND posn>18));"-";posn-(9 AND posn>9)-(9 AND posn>18) 8030 LET a=8-(7 AND posn<10)+(7 AND posn>18) 8040 LET no=posn-(18 AND a=15)-(9 AND a=8) 8050 LET p=a+(2 AND no>3)+(2 AND no>6) 8060 LET q=p-a+8 8070 LET q=q+(4 AND (no=2 OR no=5 OR no=8))+(8 AND (no=3 OR no=6 OR no=9)) 8080 BEEP .01,36: PRINT INK 7; BRIGHT 1;AT p,q;("\a" AND m=1)+("\b" AND m=0) 8500 REM search through lines 8505 LET a=9600: LET b=1 8510 FOR p=1 TO 9 8515 LET q=a(p)+a(p+9)+a(p+18) 8520 GO SUB a 8525 NEXT p 8530 FOR p=1 TO 21 8535 IF p=4 THEN LET p=10 8540 IF p=13 THEN LET p=19 8545 LET q=a(p)+a(p+3)+a(p+6) 8550 GO SUB a 8555 NEXT p 8560 FOR p=1 TO 25 STEP 3 8565 LET q=a(p)+a(p+1)+a(p+2) 8570 GO SUB a 8575 NEXT p 8580 FOR p=1 TO 3 8585 LET q=a(p)+a(p+12)+a(p+24) 8590 GO SUB a 8595 NEXT p 8600 FOR p=1 TO 7 STEP 3 8605 LET q=a(p)+a(p+10)+a(p+20) 8610 GO SUB a 8615 NEXT p 8620 FOR p=7 TO 9 8625 LET q=a(p)+a(p+6)+a(p+12) 8630 GO SUB a 8635 NEXT p 8640 FOR p=3 TO 9 STEP 3 8645 LET q=a(p)+a(p+8)+a(p+16) 8650 GO SUB a 8655 NEXT p 8660 FOR p=1 TO 19 STEP 9 8665 LET q=a(p)+a(p+4)+a(p+8) 8670 GO SUB a 8675 NEXT p 8680 FOR p=3 TO 21 STEP 9 8685 LET q=a(p)+a(p+2)+a(p+4) 8690 GO SUB a 8695 NEXT p 8710 LET q=a(1)+a(14)+a(27) 8715 GO SUB a 8720 LET q=a(3)+a(14)+a(25) 8725 GO SUB a 8730 LET q=a(7)+a(14)+a(21) 8735 GO SUB a 8740 LET q=a(9)+a(14)+a(19) 8745 GO SUB a 8750 REM Is game over? 8760 LET go=go+1 8770 IF go=27 THEN GO TO 9000 8800 REM go to next move 8810 PRINT AT 22,0,, 8820 LET m=ABS (m-1) 8830 GO TO 1000-(800 AND m) 9000 REM Count completed lines 9010 LET a=0: LET b=0 9020 FOR f=1 TO 49 9030 IF b(f)=3 THEN LET a=a+1 9040 IF b(f)=12 THEN LET b=b+1 9050 NEXT f 9200 REM Print final score 9210 PRINT AT 1,25;"You";AT 3,25;"have";AT 5,25;b;AT 7,25;"line"+("s" AND b<>1);":" 9220 PRINT AT 11,25;"I have";AT 13,25;a;AT 15,25;"line"+("s" AND a<>1);"." 9230 IF a>b THEN GO TO 9300 9240 IF b=a THEN GO TO 9400 9250 PRINT AT 22,0;"You win, darn it. Another game?" 9260 BEEP 1,-12 9270 GO TO 9430 9300 PRINT AT 22,0; FLASH 1;"I win again!"; 9310 PRINT " Another try?" 9320 FOR g=1 TO 5: FOR f=12 TO 36 STEP 10: BEEP .05,f: NEXT f: NEXT g 9330 GO TO 9430 9400 PRINT AT 22,0;" "; INVERSE 1;"DRAW"; 9410 PRINT " Another game?" 9420 BEEP .5,24 9430 GO SUB 9500 9440 IF a$<>"Y" AND a$<>"N" THEN BEEP .1,-24: GO TO 9430 9450 PRINT AT 22,0,, 9460 POKE 23659,2 9470 IF a$="Y" THEN RUN 9480 FOR f=12 TO 0 STEP -1: BEEP .05,f: NEXT f: STOP 9500 REM INKEY$ routine 9510 IF INKEY$<>"" THEN GO TO 9510 9520 IF INKEY$="" THEN GO TO 9520 9530 LET a$=INKEY$ 9540 RETURN 9600 REM store state of lines 9610 LET b(b)=q 9620 IF q=12 OR q=3 THEN BEEP .01,16+(12 AND q=3) 9630 LET b=b+1 9640 RETURN 9900 REM instructions 9910 BORDER 4: PAPER 4: INK 0: FLASH 0: BRIGHT 0: CLS 9920 PRINT AT 0,7; INVERSE 1;"3-D TIC TAC TOE" 9930 PRINT ''"The object of the game is to complete as many lines as you can. The computer will also try!" 9940 PRINT '"All straight lines count,whetherhorizontal,vertical or diagonal.There are 49 possible lines." 9950 PRINT '''"Choose a skill level:-"''TAB 4;"Press: 1 = dead easy",TAB 11;"2 = hard",TAB 11;"3 = even harder" 9960 BEEP .05,40 9970 GO SUB 9500 9980 IF a$<"1" OR a$>"3" THEN BEEP .1,-24: GO TO 9970 9990 LET level=VAL a$ 9995 CLS : RETURN 9999 SAVE "3DTICTACTO" LINE 1 ```