====Tic-tac-toe in basic (Gwbasic, qbasic and qb64 compatible) ==== Tic-tac-toe is a game with a simple logic; there are winner and loser positions. This is the reason I felt myself able to make an "AI player" able to play against a human player. ===Robot strategy=== The "brain" of the robot is in 400-750, an can be split in two parts: *First, (lines 440-460), computer "sums" the number of pieces in each row. The position of each tile in each row has been previously obtained from DATA instructions in lines 1000-1080 and stored in the LINEAS (="ROWS") matrix. The first dimension represents number of row (up to eight possible rows in the nine tiles board), the second position represents the tile (first, middle or last) in the row, and the third differences between X and Y coordinates. *Second, computer "raises" or "lowers" the value of each tile according to the number of pieces on its row: *If there are two computer pieces, (-2), the empty tile in the row get a high value (+85), since "winning" is better than "avoiding to lose". *If there are two human pieces (2), the empty tile gets a high value (+21), so we "avoid to lose". *If there is a computer piece and no human piece in the row (-1), the value given to the tile is high (+5), but not so high to choose a tile were we have three different choices to put the second piece of our row instead of stop a real threat from human player. *Last, if there is a lonely human piece in a row, the value of the tiles around it is lowered, (-1), but not so much to hide a real threat from near rows with has two human pieces. Examples: (O=human, X=computer) ^ ^ A ^ B ^ C | ^ 1| O | -1 | X | ^ 2| -1 | O | X | ^ 3| -1 | -1 | 106 | *//C3 gets 85+21+0=106, since C1..C3 vertical row has two computer pieces (+85), there is a human threat in the diagonal line (+21), and no pieces on the horizontal row.// ^ ^ A ^ B ^ C | ^ 1| O | 4 | X | ^ 2| O | X | 5 | ^ 3| 105 | O | 4 | *//A3 gets 85+21-1=105, since diagonal row has two computer pieces (+85), there is a human threat in the A1:A3 vertical line (+21), and there is a lonely human piece the A3:C3 horizontal row.// *//C2 gets 5+0=5. Vertical row C1:C2 has a lonely computer piece (+5), and there are both a human and a computer piece (+0) in the horizontal row A2:C2.// *//C3 gets 5-1=0. It is the same vertical row as C2, but the presence of a lonely human in horizontal row A3:C3 is reducing its value (-1).// 5 RANDOMIZE VAL(MID$(TIME$, 7)) 10 REM ***** Tic-tac-toe ***** 20 CLS: SCREEN 1 30 DIM BOARD(3, 3): DIM TILEVALUE(3, 3) 40 DIM ROWS(8, 3, 2): DIM BESTMOVE(9, 2) 50 RESTORE 1000 60 FOR A = 1 TO 8: FOR B = 1 TO 3 70 READ ROWS(A, B, 1), ROWS(A, B, 2) 80 NEXT: NEXT 90 LINE (150, 20)-(150, 80): LINE (170, 20)-(170, 80): LINE (130, 40)-(190, 40): LINE (190, 60)-(130, 60) 100 REM ***** Beginning of game ***** 110 TURNS = 0 120 VIEW PRINT 16 TO 24: CLS 2: GOTO 5000 200 REM ***** Human moves ***** 210 VIEW PRINT 16 TO 24: CLS 2 220 LOCATE 16, 1: INPUT "Where do you want to move? (Use letter for column, number for row)"; A$ 230 IF LEN(A$) <> 2 THEN PRINT "Invalid coordinates": GOTO 210 240 A1$ = MID$(A$, 1, 1) 250 IF A1$ > "Z" THEN A1$ = CHR$(ASC(A1$) - 32) 260 IF A1$ > "C" OR A1$ < "A" THEN PRINT "Please input a valid column: from A to C.": GOTO 210 270 X = ASC(A1$) + 1 - ASC("A") 280 A2$ = MID$(A$, 2, 1) 290 IF A2$ < "1" OR A2$ > "3" THEN PRINT "Please input a valid row: from 1 to 3.": GOTO 210 300 Y = VAL(A2$) 310 IF BOARD(X, Y) <> 0 THEN PRINT "Tile is already full.": GOTO 210 320 PLAYER = 1: GOSUB 2000 330 BOARD(X, Y) = 1 340 GOSUB 3000 350 TURNS = TURNS + 1: IF TURNS >= 9 THEN GOTO 4010 400 REM ***** Computer moves ***** 410 REM ***** Row appraisal ***** 420 FOR F=1 TO 3:FOR G=1 TO 3:TILEVALUE(F,G)=0:NEXT :NEXT 430 FOR A=1 TO 8:FULLLINE=0 440 FOR B=1 TO 3 450 FULLLINE=FULLLINE+BOARD(ROWS(A,B,1),ROWS(A,B,2)) 460 NEXT 470 FOR B=1 TO 3 480 XL=ROWS(A,B,1):YL=ROWS(A,B,2) 490 IF FULLLINE=1 THEN TILEVALUE(XL,YL)=TILEVALUE(XL,YL)+1 500 IF FULLLINE=-1 THEN TILEVALUE(XL,YL)=TILEVALUE(XL,YL)+5 510 IF FULLLINE=2 THEN TILEVALUE(XL,YL)=TILEVALUE(XL,YL)+21 520 IF FULLLINE=-2 THEN TILEVALUE(XL,YL)=TILEVALUE(XL,YL)+85 530 NEXT 540 NEXT 550 MAXIMUM=0:FOR A=1 TO 3:FOR B=1 TO 3 560 IF BOARD(A,B)<>0 THEN TILEVALUE(A,B)=-1 570 IF TILEVALUE(A,B)>MAXIMUM THEN MAXIMUM=TILEVALUE(A,B) 580 NEXT :NEXT 590 BESTCOUNT=0 600 FOR A=1 TO 3:FOR B=1 TO 3 610 IF TILEVALUE(A,B)=MAXIMUM THEN BESTCOUNT=BESTCOUNT+1:BESTMOVE(BESTCOUNT,1)=A:BESTMOVE(BESTCOUNT,2)=B 620 NEXT :NEXT 630 MYMOVE=INT(RND*BESTCOUNT-1)+1 640 IF MYMOVE=0 THEN PRINT "ERROR: MYMOVE=0":MYMOVE=1 650 IF MYMOVE>9 THEN PRINT "ERROR: MYMOVE>9":MYMOVE=9 660 X=BESTMOVE(MYMOVE,1) 670 Y=BESTMOVE(MYMOVE,2) 680 IF MAXIMUM<=4 AND BOARD(2,2)=0 THEN X=2:Y=2 690 PRINT "My move:";CHR$(ASC("A")+X-1);Y 700 IF BOARD(X,Y)<>0 THEN PRINT "Tile already full":GOTO 630 710 PLAYER =2 :GOSUB 2000 720 BOARD(X,Y)=-1 730 GOSUB 3000 740 TURNS=TURNS+1:IF TURNS>=9 THEN GOTO 4010 750 GOTO 210 1000 REM Store data for the 9 possible rows 1010 DATA 1,1,1,2,1,3: REM row 1 1020 DATA 2,1,2,2,2,3: REM row 2 1030 DATA 3,1,3,2,3,3: REM row 3 1040 DATA 1,1,2,1,3,1: REM column 1 1050 DATA 1,2,2,2,3,2: REM column 2 1060 DATA 1,3,2,3,3,3: REM column 3 1070 DATA 1,1,2,2,3,3: REM diag. 1 1080 DATA 3,1,2,2,1,3: REM diag. 2 2000 REM Draw cross or circle 2010 IF PLAYER = 1 THEN GOTO 2040 2020 CIRCLE (120 + 20 * X, 10 + 20 * Y), 10, 1 2030 RETURN 2040 LINE (110 + 20 * X, 20 * Y)-(130 + 20 * X, 20 + 20 * Y), 2 2050 LINE (110 + 20 * X, 20 + 20 * Y)-(130 + 20 * X, 20 * Y), 2 2060 RETURN 3000 REM ***** Three in a row? ***** 3010 FOR A = 1 TO 8 3020 FULLLINE = 0: FOR B = 1 TO 3 3030 FULLLINE = FULLLINE + BOARD(ROWS(A, B, 1), ROWS(A, B, 2)) 3040 NEXT 3050 IF FULLLINE = 3 THEN PRINT "Tic tac toe! You won!": GOTO 4010 3060 IF FULLLINE = -3 THEN PRINT "Tic tac toe! I won!": GOTO 4010 3070 NEXT 3080 RETURN 4000 REM ***** Play again? ***** 4010 INPUT "Do you want to play again?"; A$ 4020 IF MID$(A$, 1, 1) = "Y" OR MID$(A$, 1, 1) = "y" THEN RUN 4030 IF MID$(A$, 1, 1) = "N" OR MID$(A$, 1, 1) = "n" THEN END 4040 PRINT "Please input 'Y' for 'yes', 'N' for 'no'": GOTO 4010 5000 REM ***** Decide starting player ***** 5010 INPUT "1- I start 2- You start"; N 5020 IF N = 1 THEN GOTO 400 5030 IF N = 2 THEN GOTO 200 5040 GOTO 5000