#! /usr/local/bin/bigforth \ four in a row game 6 Value #rows 7 Value #cols 4 Value #win #rows 2 + Value *rows #cols 2 + Value *cols 8 Value #depth \ board data base Create board here *rows *cols * dup allot erase \ board operations: push stone and display result [DEFINED] cx@ 0= [IF] : cx@ ( addr -- c ) c@ dup $80 and negate or ; [THEN] : b[] ( x y -- board[x,y] ) *rows * + [ board *rows 1+ + ] ALiteral + ; : .board ( -- ) cr ." -0123456" #rows 0 ?DO cr I 0 .r #cols 0 ?DO J I b[] cx@ 1 min -1 max 1+ s" x.o" drop + c@ emit LOOP LOOP ; Variable cur-stone : seeker DOES> @ ( addr index -- n ) over #win 0 ?DO over + dup cx@ cur-stone @ * 0<= ?LEAVE LOOP swap >r - negate r> /f 1- ; : seek ( n -- ) Create dup , seeker Create negate , seeker ; 1 seek >left >right *rows seek >up >down *rows 1- seek >lu >rd *rows 1+ seek >ld >ru : score? ( boardp -- score-addr ) >r r@ >left r@ >right + r@ >up r@ >down + max r@ >lu r@ >rd + max r@ >ld r@ >ru + max 1+ cur-stone @ * r@ c! r> ; : stone ( side col -- score-addr ) over cur-stone ! 0 swap b[] #rows 0 skip drop 1- tuck c! score? ; Variable gameover gameover on : stone? ( n col -- ) stone cx@ abs #win >= gameover ! ; \ alpha-beta min-max strategy Variable side -1 side ! : = IF dup * + ELSE swap >r dup * + r> THEN LOOP side @ 0< IF swap THEN over swap - * 8* 7 random + ; \ alpha-beta-min-max: Same evaluation for both sides; \ just negate the score of the other side \ start with minimal possible score; leave with maximal score if you win \ otherwise check score of next half-move \ leave if better than beta \ update alpha if current score is less $7FFFFFFF Constant negate Constant 1- Constant negate Constant 2/ 1+ Constant Create min-max# $20 cells allot : eval-min-max ( beta n -- score best ) 1 over cells min-max# + +! dup 0= IF 2drop leaf-score 0 EXIT THEN /side -1 ( beta n best alpha ) #cols 0 ?DO 0 I b[] cx@ 0= IF side @ I stone >r r@ cx@ abs #win >= IF r> LEAVE THEN 2over 1- swap >r over negate swap recurse drop dup /f - negate r> r> IF drop nip nip I swap LEAVE THEN drop \ if score better than alpha, new score is best one 2dup < IF nip nip I swap ELSE drop THEN THEN LOOP swap 2swap 2drop /side ; : c ( -- score best ) min-max# $20 cells erase -1 side ! #depth eval-min-max \ min-max# #depth 1+ cells bounds ?DO I ? cell +LOOP space dup . cr 1 over stone? ; : 4init gameover off board *rows *cols * erase ; : h ( n -- ) gameover @ IF 4init cr ." New game" THEN dup #cols 0 within abort" sorry, outside the field" 0 over b[] cx@ abort" sorry, column already full" -1 swap stone? gameover @ 0= IF c drop #depth + <= IF ." I'm going to lose" ELSE gameover @ IF ." I win" THEN THEN ELSE ." you win" THEN true #cols 0 ?DO 0 I b[] cx@ 0<> and LOOP IF ." tie" gameover on THEN .board ;