2024-07-11 15:23:25 +02:00
|
|
|
( Prove you can't win at tic-tac-toe if the opponent is competent. )
|
|
|
|
( Expected visited board positions: 6493 )
|
|
|
|
|
|
|
|
( board: 0 1 2 )
|
|
|
|
( 3 4 5 )
|
|
|
|
( 6 7 8 )
|
|
|
|
( notes: )
|
|
|
|
( I tried using a DO loop in MINMAX but apparently "I" isn't preserved on recursion. )
|
|
|
|
( Also, breaking out of the DO loop broke out across recursion stack frames, which won't work. )
|
|
|
|
( That's why I use the "10 boardIndex !" hack to break out of the loop instead. )
|
|
|
|
|
|
|
|
( true global variables )
|
2024-07-10 21:11:53 +02:00
|
|
|
VARIABLE board 9 ALLOT
|
|
|
|
VARIABLE moves
|
2024-07-11 15:23:25 +02:00
|
|
|
VARIABLE recursionDepth
|
|
|
|
|
|
|
|
( effectively locals in MINMAX )
|
2024-07-10 21:11:53 +02:00
|
|
|
VARIABLE alpha
|
|
|
|
VARIABLE beta
|
2024-07-11 15:23:25 +02:00
|
|
|
VARIABLE pieceMove
|
2024-07-10 21:11:53 +02:00
|
|
|
VARIABLE val
|
|
|
|
VARIABLE boardIndex
|
|
|
|
VARIABLE score
|
|
|
|
|
|
|
|
6 CONSTANT scoreWin
|
|
|
|
5 CONSTANT scoreTie
|
|
|
|
4 CONSTANT scoreLose
|
|
|
|
9 CONSTANT scoreMax
|
|
|
|
2 CONSTANT scoreMin
|
|
|
|
0 CONSTANT scoreInvalid
|
|
|
|
|
|
|
|
0 CONSTANT pieceBlank
|
|
|
|
1 CONSTANT pieceX
|
|
|
|
2 CONSTANT pieceO
|
|
|
|
|
|
|
|
board 0 + CONSTANT B0
|
|
|
|
board 1 + CONSTANT B1
|
|
|
|
board 2 + CONSTANT B2
|
|
|
|
board 3 + CONSTANT B3
|
|
|
|
board 4 + CONSTANT B4
|
|
|
|
board 5 + CONSTANT B5
|
|
|
|
board 6 + CONSTANT B6
|
|
|
|
board 7 + CONSTANT B7
|
|
|
|
board 8 + CONSTANT B8
|
|
|
|
|
|
|
|
: LOOKFORWINNER
|
2024-07-11 15:23:25 +02:00
|
|
|
B4 C@
|
|
|
|
DUP pieceBlank <> IF
|
|
|
|
DUP B0 C@ = IF DUP B8 C@ = IF EXIT THEN THEN
|
|
|
|
DUP B1 C@ = IF DUP B7 C@ = IF EXIT THEN THEN
|
|
|
|
DUP B2 C@ = IF DUP B6 C@ = IF EXIT THEN THEN
|
|
|
|
DUP B3 C@ = IF DUP B5 C@ = IF EXIT THEN THEN
|
|
|
|
THEN
|
|
|
|
DROP
|
|
|
|
|
2024-07-10 21:11:53 +02:00
|
|
|
B0 C@
|
|
|
|
DUP pieceBlank <> IF
|
|
|
|
DUP B1 C@ = IF DUP B2 C@ = IF EXIT THEN THEN
|
|
|
|
DUP B3 C@ = IF DUP B6 C@ = IF EXIT THEN THEN
|
|
|
|
THEN
|
|
|
|
DROP
|
|
|
|
|
2024-07-11 15:23:25 +02:00
|
|
|
B8 C@
|
2024-07-10 21:11:53 +02:00
|
|
|
DUP pieceBlank <> IF
|
2024-07-11 15:23:25 +02:00
|
|
|
DUP B2 C@ = IF DUP B5 C@ = IF EXIT THEN THEN
|
|
|
|
DUP B6 C@ = IF DUP B7 C@ = IF EXIT THEN THEN
|
2024-07-10 21:11:53 +02:00
|
|
|
THEN
|
|
|
|
DROP
|
|
|
|
|
|
|
|
pieceBlank
|
|
|
|
;
|
|
|
|
|
|
|
|
: dumpboard
|
|
|
|
." board: "
|
|
|
|
9 0 DO
|
|
|
|
I board + C@ .
|
|
|
|
LOOP
|
|
|
|
CR
|
|
|
|
;
|
|
|
|
|
|
|
|
: MINMAX ( stack: alpha beta )
|
|
|
|
1 moves +!
|
|
|
|
0 val !
|
|
|
|
|
|
|
|
recursionDepth @ 3 > IF
|
|
|
|
LOOKFORWINNER
|
|
|
|
DUP pieceBlank <> IF
|
|
|
|
pieceX = IF scoreWin ELSE scoreLose THEN
|
|
|
|
val !
|
|
|
|
ELSE
|
2024-07-11 15:23:25 +02:00
|
|
|
DROP
|
|
|
|
recursionDepth @ 8 = IF scoreTie val ! THEN
|
2024-07-10 21:11:53 +02:00
|
|
|
THEN
|
|
|
|
THEN
|
|
|
|
|
|
|
|
0 val @ = IF
|
|
|
|
recursionDepth @ 1 AND IF
|
|
|
|
scoreMin val !
|
|
|
|
pieceX pieceMove !
|
|
|
|
ELSE
|
|
|
|
scoreMax val !
|
|
|
|
pieceO pieceMove !
|
|
|
|
THEN
|
|
|
|
|
|
|
|
beta !
|
|
|
|
alpha !
|
2024-07-11 15:23:25 +02:00
|
|
|
alpha @
|
|
|
|
beta @
|
2024-07-10 21:11:53 +02:00
|
|
|
0 boardIndex !
|
|
|
|
|
|
|
|
BEGIN boardIndex @ 9 < WHILE
|
|
|
|
boardIndex @ board + C@ 0 = IF
|
|
|
|
pieceMove @ board boardIndex @ + C!
|
2024-07-11 15:23:25 +02:00
|
|
|
boardIndex @ pieceMove @ val @
|
2024-07-10 21:11:53 +02:00
|
|
|
1 recursionDepth +!
|
2024-07-11 15:23:25 +02:00
|
|
|
|
2024-07-10 21:11:53 +02:00
|
|
|
alpha @ beta @ RECURSE
|
2024-07-11 15:23:25 +02:00
|
|
|
|
2024-07-10 21:11:53 +02:00
|
|
|
-1 recursionDepth +!
|
|
|
|
score !
|
2024-07-11 15:23:25 +02:00
|
|
|
beta ! alpha ! val ! pieceMove ! boardIndex !
|
|
|
|
pieceBlank boardIndex @ board + C!
|
2024-07-10 21:11:53 +02:00
|
|
|
|
|
|
|
pieceX pieceMove @ = IF
|
|
|
|
score @ val @ > IF
|
|
|
|
score @ val !
|
|
|
|
scoreWin val @ = val @ beta @ < INVERT OR IF
|
|
|
|
10 boardIndex !
|
|
|
|
ELSE
|
|
|
|
val @ alpha @ > IF val @ alpha ! THEN
|
|
|
|
THEN
|
|
|
|
THEN
|
|
|
|
ELSE
|
|
|
|
score @ val @ < IF
|
|
|
|
score @ val !
|
|
|
|
scoreLose val @ = val @ alpha @ > INVERT OR IF
|
|
|
|
10 boardIndex !
|
|
|
|
ELSE
|
|
|
|
val @ beta @ < IF val @ beta ! THEN
|
|
|
|
THEN
|
|
|
|
THEN
|
|
|
|
THEN
|
|
|
|
THEN
|
|
|
|
1 boardIndex +!
|
|
|
|
REPEAT
|
|
|
|
THEN
|
|
|
|
|
|
|
|
val @
|
|
|
|
;
|
|
|
|
|
|
|
|
: RUNIT ( move -- )
|
|
|
|
pieceX
|
2024-07-11 15:23:25 +02:00
|
|
|
OVER board + C! ( make the move )
|
2024-07-10 21:11:53 +02:00
|
|
|
0 recursionDepth !
|
|
|
|
scoreMin scoreMax MINMAX
|
|
|
|
|
|
|
|
scoreTie <> IF ." there's a bug somewhere" THEN
|
2024-07-11 15:23:25 +02:00
|
|
|
DROP DROP ( remove alpha and beta )
|
2024-07-10 21:11:53 +02:00
|
|
|
|
|
|
|
pieceBlank
|
2024-07-11 15:23:25 +02:00
|
|
|
SWAP board + C! ( restore the board to the original state )
|
2024-07-10 21:11:53 +02:00
|
|
|
;
|
|
|
|
|
|
|
|
: TTT
|
2024-07-11 15:23:25 +02:00
|
|
|
board 9 pieceBlank FILL
|
2024-07-10 21:11:53 +02:00
|
|
|
|
2024-07-11 15:23:25 +02:00
|
|
|
( all other first moves are reflections of these 3 )
|
2024-07-10 21:11:53 +02:00
|
|
|
10 0 DO
|
|
|
|
0 moves !
|
2024-07-11 15:23:25 +02:00
|
|
|
0 RUNIT
|
|
|
|
1 RUNIT
|
|
|
|
4 RUNIT
|
2024-07-10 21:11:53 +02:00
|
|
|
LOOP
|
|
|
|
|
2024-07-11 15:23:25 +02:00
|
|
|
." 10 iterations" CR
|
|
|
|
." moves evaluated: " moves @ . CR
|
2024-07-10 21:11:53 +02:00
|
|
|
;
|