; ;============== Global Variables =============== ; (defglobal ?*GlobalBoard* = (create$ )) ;A multifield variable for storing the board (square 1 to square 64) (defglobal ?*FlippingDiscs* = (create$ )) ;A multifield variable for storing the discs that need to be flipped when a new move occurs (defglobal ?*MyAvailMoves* = (create$ )) ;A multifield variable for storing the available moves for this program robot (defglobal ?*OpAvailMoves* = (create$ )) ;A multifield variable for storing the opponent (defglobal ?*Phase* = opening) ; ;A variable for storing the phase that the game is being at. Values are opening/middle/ending. (defglobal ?*NewMove* = (create$ )) ;A multifield variable that stores the position of the newly placed move for printing. (x, y) (defglobal ?*Corners* = (create$ 1 8 57 64)) ;A multifield variable that stores the NO of the Corners (defglobal ?*ASquares* = (create$ 3 6 17 24 41 48 59 62)) ;A multifield variable that stores the NO of the ASquares (defglobal ?*BSquares* = (create$ 4 5 25 32 33 40 60 61)) ;A multifield variable that stores the NO of the BSquares (defglobal ?*CSquares* = (create$ 2 7 9 16 49 56 58 63)) ;A multifield variable that stores the NO of the CSquares (defglobal ?*XSquares* = (create$ 10 15 50 55)) ;A multifield variable that stores the NO of the XSquares (defglobal ?*MyAvailMoveWeights* = (create$ )) ;the list of weights of each element in ?*MyAvailMoves* ; ;============== Functions =============== ; ;------------------ Other functions ------------------ ; ; Compute the phase that the game is being at. The result (opening, middle or ending) is stored as ?*Phase* ; (deffunction computePhase () (bind ?count 0) (loop-for-count (?i 1 64) do (bind ?ele (nth$ ?i ?*GlobalBoard*)) (if (<> ?ele 0) then (bind ?count (+ ?count 1))) ) (if (<= ?count 15) then (bind ?*Phase* opening)) (if (>= ?count 50) then (bind ?*Phase* ending)) (if (and (> ?count 15) (< ?count 50)) then (bind ?*Phase* middle)) ) ; Mark the squares that need to be flipped after a disc is placed. ; The No.s of these discs are stored as a list in ?*FlippingDiscs*. ; (deffunction markFlippingDiscs (?x ?y ?turnNo) (bind ?j 0) (bind ?k 0) (bind ?*FlippingDiscs* (insert$ ?*FlippingDiscs* (+ 1 (length$ ?*FlippingDiscs*)) (+ (* ?x 8) ?y 1))) ;Look into 8 directions ;East (bind ?available false) (if (< ?y 6) then (bind ?ele (nth$ (+ (* ?x 8) ?y 2) ?*GlobalBoard*)) ;(x, y+1) ;(printout t ":" ?ele crlf) (if (= ?ele (- 0 ?turnNo)) then (bind ?j (+ ?y 2)) (while (< ?j 8) do ;j <- y+2..7 (bind ?ele1 (nth$ (+ (* ?x 8) ?j 1) ?*GlobalBoard*)); (x, j) (if (= ?ele1 0) then (break)) (if (<> ?ele1 ?ele) then (bind ?available true) (break)) (bind ?j (+ ?j 1)) ))) (if (eq ?available true) then (loop-for-count (?m (+ ?y 1) (- ?j 1)) (bind ?*FlippingDiscs* (insert$ ?*FlippingDiscs* (+ 1 (length$ ?*FlippingDiscs*)) (+ (* ?x 8) ?m 1))))) ;West (bind ?available false) (if (> ?y 1) then (bind ?ele (nth$ (+ (* ?x 8) ?y) ?*GlobalBoard*)) ;(x, y-1) ;(printout t ":" ?ele crlf) (if (= ?ele (- 0 ?turnNo)) then (bind ?j (- ?y 2)) (while (>= ?j 0) do ;j <- y-2..0 (bind ?ele1 (nth$ (+ (* ?x 8) ?j 1) ?*GlobalBoard*)); (x, j) (if (= ?ele1 0) then (break)) (if (<> ?ele1 ?ele) then (bind ?available true) (break)) (bind ?j (- ?j 1)) ))) (if (eq ?available true) then (loop-for-count (?m (+ ?j 1) (- ?y 1)) (bind ?*FlippingDiscs* (insert$ ?*FlippingDiscs* (+ 1 (length$ ?*FlippingDiscs*)) (+ (* ?x 8) ?m 1))))) ;South (bind ?available false) (if (< ?x 6) then (bind ?ele (nth$ (+ (* (+ ?x 1) 8) ?y 1) ?*GlobalBoard*)) ;(x+1, y) ;(printout t ":" ?ele crlf) (if (= ?ele (- 0 ?turnNo)) then (bind ?j (+ ?x 2)) (while (< ?j 8) do ;j <- x+2..7 (bind ?ele1 (nth$ (+ (* ?j 8) ?y 1) ?*GlobalBoard*)); (j, y) (if (= ?ele1 0) then (break)) (if (<> ?ele1 ?ele) then (bind ?available true) (break)) (bind ?j (+ ?j 1)) ))) (if (eq ?available true) then (loop-for-count (?m (+ ?x 1) (- ?j 1)) (bind ?*FlippingDiscs* (insert$ ?*FlippingDiscs* (+ 1 (length$ ?*FlippingDiscs*)) (+ (* ?m 8) ?y 1))))) ;North (bind ?available false) (if (> ?x 1) then (bind ?ele (nth$ (+ (* (- ?x 1) 8) ?y 1) ?*GlobalBoard*)) ;(x-1, y) ;(printout t ":" ?ele crlf) (if (= ?ele (- 0 ?turnNo)) then (bind ?j (- ?x 2)) (while (>= ?j 0) do ;j <- x-2..0 (bind ?ele1 (nth$ (+ (* ?j 8) ?y 1) ?*GlobalBoard*)); (j, y) (if (= ?ele1 0) then (break)) (if (<> ?ele1 ?ele) then (bind ?available true) (break)) (bind ?j (- ?j 1)) ))) (if (eq ?available true) then (loop-for-count (?m (+ ?j 1) (- ?x 1)) (bind ?*FlippingDiscs* (insert$ ?*FlippingDiscs* (+ 1 (length$ ?*FlippingDiscs*)) (+ (* ?m 8) ?y 1))))) ;SouthEast (bind ?available false) (if (and (< ?x 6) (< ?y 6)) then (bind ?ele (nth$ (+ (* (+ ?x 1) 8) ?y 2) ?*GlobalBoard*)) ;(x+1, y+1) ;(printout t ":" ?ele crlf) (if (= ?ele (- 0 ?turnNo)) then (bind ?j (+ ?x 2)) (bind ?k (+ ?y 2)) (while (and (< ?j 8) (< ?k 8)) do ;j <- x+2..7, k <- y+2..7 (bind ?ele1 (nth$ (+ (* ?j 8) ?k 1) ?*GlobalBoard*)); (j, k) (if (= ?ele1 0) then (break)) (if (<> ?ele1 ?ele) then (bind ?available true) (break)) (bind ?j (+ ?j 1)) (bind ?k (+ ?k 1)) ))) (if (eq ?available true) then (bind ?m (+ ?x 1)) (bind ?n (+ ?y 1)) (loop-for-count (abs (- ?x (- ?j 1))) (bind ?*FlippingDiscs* (insert$ ?*FlippingDiscs* (+ 1 (length$ ?*FlippingDiscs*)) (+ (* ?m 8) ?n 1))) (bind ?m (+ ?m 1)) (bind ?n (+ ?n 1)))) ;SouthWest (bind ?available false) (if (and (< ?x 6) (> ?y 1)) then (bind ?ele (nth$ (+ (* (+ ?x 1) 8) ?y) ?*GlobalBoard*)) ;(x+1, y-1) ;(printout t ":" ?ele crlf) (if (= ?ele (- 0 ?turnNo)) then (bind ?j (+ ?x 2)) (bind ?k (- ?y 2)) (while (and (< ?j 8) (>= ?k 0)) do ;j <- x+2..7, k <- y-2..0 (bind ?ele1 (nth$ (+ (* ?j 8) ?k 1) ?*GlobalBoard*)); (j, k) (if (= ?ele1 0) then (break)) (if (<> ?ele1 ?ele) then (bind ?available true) (break)) (bind ?j (+ ?j 1)) (bind ?k (- ?k 1)) ))) (if (eq ?available true) then (bind ?m (+ ?x 1)) (bind ?n (- ?y 1)) (loop-for-count (abs (- ?x (- ?j 1))) (bind ?*FlippingDiscs* (insert$ ?*FlippingDiscs* (+ 1 (length$ ?*FlippingDiscs*)) (+ (* ?m 8) ?n 1))) (bind ?m (+ ?m 1)) (bind ?n (- ?n 1)))) ;NorthEast (bind ?available false) (if (and (> ?x 1) (< ?y 6)) then (bind ?ele (nth$ (+ (* (- ?x 1) 8) ?y 2) ?*GlobalBoard*)) ;(x-1, y+1) ;(printout t ":" ?ele crlf) (if (= ?ele (- 0 ?turnNo)) then (bind ?j (- ?x 2)) (bind ?k (+ ?y 2)) (while (and (>= ?j 0) (< ?k 8)) do ;j <- x-2..0, k <- y+2..7 (bind ?ele1 (nth$ (+ (* ?j 8) ?k 1) ?*GlobalBoard*)); (j, k) (if (= ?ele1 0) then (break)) (if (<> ?ele1 ?ele) then (bind ?available true) (break)) (bind ?j (- ?j 1)) (bind ?k (+ ?k 1)) ))) (if (eq ?available true) then (bind ?m (- ?x 1)) (bind ?n (+ ?y 1)) (loop-for-count (abs (- ?x (+ ?j 1))) (bind ?*FlippingDiscs* (insert$ ?*FlippingDiscs* (+ 1 (length$ ?*FlippingDiscs*)) (+ (* ?m 8) ?n 1))) (bind ?m (- ?m 1)) (bind ?n (+ ?n 1)))) ;NorthWest (bind ?available false) (if (and (> ?x 1) (> ?y 1)) then (bind ?ele (nth$ (+ (* (- ?x 1) 8) ?y) ?*GlobalBoard*)) ;(x-1, y-1) ;(printout t ":" ?ele crlf) (if (= ?ele (- 0 ?turnNo)) then (bind ?j (- ?x 2)) (bind ?k (- ?y 2)) (while (and (>= ?j 0) (>= ?k 0)) do ;j <- x-2..0, k <- y-2..0 (bind ?ele1 (nth$ (+ (* ?j 8) ?k 1) ?*GlobalBoard*)); (j, k) (if (= ?ele1 0) then (break)) (if (<> ?ele1 ?ele) then (bind ?available true) (break)) (bind ?j (- ?j 1)) (bind ?k (- ?k 1)) ))) (if (eq ?available true) then (bind ?m (- ?x 1)) (bind ?n (- ?y 1)) (loop-for-count (abs (- ?x (+ ?j 1))) (bind ?*FlippingDiscs* (insert$ ?*FlippingDiscs* (+ 1 (length$ ?*FlippingDiscs*)) (+ (* ?m 8) ?n 1))) (bind ?m (- ?m 1)) (bind ?n (- ?n 1)))) ) ; Mark the available moves for the next move for either the opponent and myself (program). ; The No.s of these discs are stored as a list in ?*OpAvailMoves* or ?*MyAvailMoves* ; (deffunction markAvailMoves (?i ?role) (bind ?x (div (- ?i 1) 8)) (bind ?y (mod (- ?i 1) 8)) ;x, y ;Look into 8 directions ;East (bind ?available false) (if (< ?y 6) then (bind ?ele (nth$ (+ (* ?x 8) ?y 2) ?*GlobalBoard*)) ;(x, y+1) ;(printout t ":" ?ele crlf) (if (<> ?ele 0) then (bind ?j (+ ?y 2)) (while (< ?j 8) do ;j <- y+2..7 (bind ?ele1 (nth$ (+ (* ?x 8) ?j 1) ?*GlobalBoard*)); (x, j) (if (= ?ele1 0) then (break)) (if (<> ?ele1 ?ele) then (bind ?available true)) (bind ?j (+ ?j 1)) ))) (if (eq ?available true) ;Be careful not to add the same index in twice. then (if (= ?ele ?role) then (if (eq FALSE (member$ ?i ?*OpAvailMoves*)) then (bind ?*OpAvailMoves* (insert$ ?*OpAvailMoves* (+ 1 (length$ ?*OpAvailMoves*)) ?i))) else (if (eq FALSE (member$ ?i ?*MyAvailMoves*)) then (bind ?*MyAvailMoves* (insert$ ?*MyAvailMoves* (+ 1 (length$ ?*MyAvailMoves*)) ?i))))) ;West (bind ?available false) (if (> ?y 1) then (bind ?ele (nth$ (+ (* ?x 8) ?y) ?*GlobalBoard*)) ;(x, y-1) ;(printout t ":" ?ele crlf) (if (<> ?ele 0) then (bind ?j (- ?y 2)) (while (>= ?j 0) do ;j <- y-2..0 (bind ?ele1 (nth$ (+ (* ?x 8) ?j 1) ?*GlobalBoard*)); (x, j) (if (= ?ele1 0) then (break)) (if (<> ?ele1 ?ele) then (bind ?available true)) (bind ?j (- ?j 1)) ))) (if (eq ?available true) then (if (= ?ele ?role) then (if (eq FALSE (member$ ?i ?*OpAvailMoves*)) then (bind ?*OpAvailMoves* (insert$ ?*OpAvailMoves* (+ 1 (length$ ?*OpAvailMoves*)) ?i))) else (if (eq FALSE (member$ ?i ?*MyAvailMoves*)) then (bind ?*MyAvailMoves* (insert$ ?*MyAvailMoves* (+ 1 (length$ ?*MyAvailMoves*)) ?i))))) ;South (bind ?available false) (if (< ?x 6) then (bind ?ele (nth$ (+ (* (+ ?x 1) 8) ?y 1) ?*GlobalBoard*)) ;(x+1, y) ;(printout t ":" ?ele crlf) (if (<> ?ele 0) then (bind ?j (+ ?x 2)) (while (< ?j 8) do ;j <- x+2..7 (bind ?ele1 (nth$ (+ (* ?j 8) ?y 1) ?*GlobalBoard*)); (j, y) (if (= ?ele1 0) then (break)) (if (<> ?ele1 ?ele) then (bind ?available true)) (bind ?j (+ ?j 1)) ))) (if (eq ?available true) then (if (= ?ele ?role) then (if (eq FALSE (member$ ?i ?*OpAvailMoves*)) then (bind ?*OpAvailMoves* (insert$ ?*OpAvailMoves* (+ 1 (length$ ?*OpAvailMoves*)) ?i))) else (if (eq FALSE (member$ ?i ?*MyAvailMoves*)) then (bind ?*MyAvailMoves* (insert$ ?*MyAvailMoves* (+ 1 (length$ ?*MyAvailMoves*)) ?i))))) ;North (bind ?available false) (if (> ?x 1) then (bind ?ele (nth$ (+ (* (- ?x 1) 8) ?y 1) ?*GlobalBoard*)) ;(x-1, y) ;(printout t ":" ?ele crlf) (if (<> ?ele 0) then (bind ?j (- ?x 2)) (while (>= ?j 0) do ;j <- x-2..0 (bind ?ele1 (nth$ (+ (* ?j 8) ?y 1) ?*GlobalBoard*)); (j, y) (if (= ?ele1 0) then (break)) (if (<> ?ele1 ?ele) then (bind ?available true)) (bind ?j (- ?j 1)) ))) (if (eq ?available true) then (if (= ?ele ?role) then (if (eq FALSE (member$ ?i ?*OpAvailMoves*)) then (bind ?*OpAvailMoves* (insert$ ?*OpAvailMoves* (+ 1 (length$ ?*OpAvailMoves*)) ?i))) else (if (eq FALSE (member$ ?i ?*MyAvailMoves*)) then (bind ?*MyAvailMoves* (insert$ ?*MyAvailMoves* (+ 1 (length$ ?*MyAvailMoves*)) ?i))))) ;SouthEast (bind ?available false) (if (and (< ?x 6) (< ?y 6)) then (bind ?ele (nth$ (+ (* (+ ?x 1) 8) ?y 2) ?*GlobalBoard*)) ;(x+1, y+1) ;(printout t ":" ?ele crlf) (if (<> ?ele 0) then (bind ?j (+ ?x 2)) (bind ?k (+ ?y 2)) (while (and (< ?j 8) (< ?k 8)) do ;j <- x+2..7, k <- y+2..7 (bind ?ele1 (nth$ (+ (* ?j 8) ?k 1) ?*GlobalBoard*)); (j, k) (if (= ?ele1 0) then (break)) (if (<> ?ele1 ?ele) then (bind ?available true)) (bind ?j (+ ?j 1)) (bind ?k (+ ?k 1)) ))) (if (eq ?available true) then (if (= ?ele ?role) then (if (eq FALSE (member$ ?i ?*OpAvailMoves*)) then (bind ?*OpAvailMoves* (insert$ ?*OpAvailMoves* (+ 1 (length$ ?*OpAvailMoves*)) ?i))) else (if (eq FALSE (member$ ?i ?*MyAvailMoves*)) then (bind ?*MyAvailMoves* (insert$ ?*MyAvailMoves* (+ 1 (length$ ?*MyAvailMoves*)) ?i))))) ;SouthWest (bind ?available false) (if (and (< ?x 6) (> ?y 1)) then (bind ?ele (nth$ (+ (* (+ ?x 1) 8) ?y) ?*GlobalBoard*)) ;(x+1, y-1) ;(printout t ":" ?ele crlf) (if (<> ?ele 0) then (bind ?j (+ ?x 2)) (bind ?k (- ?y 2)) (while (and (< ?j 8) (>= ?k 0)) do ;j <- x+2..7, k <- y-2..0 (bind ?ele1 (nth$ (+ (* ?j 8) ?k 1) ?*GlobalBoard*)); (j, k) (if (= ?ele1 0) then (break)) (if (<> ?ele1 ?ele) then (bind ?available true)) (bind ?j (+ ?j 1)) (bind ?k (- ?k 1)) ))) (if (eq ?available true) then (if (= ?ele ?role) then (if (eq FALSE (member$ ?i ?*OpAvailMoves*)) then (bind ?*OpAvailMoves* (insert$ ?*OpAvailMoves* (+ 1 (length$ ?*OpAvailMoves*)) ?i))) else (if (eq FALSE (member$ ?i ?*MyAvailMoves*)) then (bind ?*MyAvailMoves* (insert$ ?*MyAvailMoves* (+ 1 (length$ ?*MyAvailMoves*)) ?i))))) ;NorthEast (bind ?available false) (if (and (> ?x 1) (< ?y 6)) then (bind ?ele (nth$ (+ (* (- ?x 1) 8) ?y 2) ?*GlobalBoard*)) ;(x-1, y+1) ;(printout t ":" ?ele crlf) (if (<> ?ele 0) then (bind ?j (- ?x 2)) (bind ?k (+ ?y 2)) (while (and (>= ?j 0) (< ?k 8)) do ;j <- x-2..0, k <- y+2..7 (bind ?ele1 (nth$ (+ (* ?j 8) ?k 1) ?*GlobalBoard*)); (j, k) (if (= ?ele1 0) then (break)) (if (<> ?ele1 ?ele) then (bind ?available true)) (bind ?j (- ?j 1)) (bind ?k (+ ?k 1)) ))) (if (eq ?available true) then (if (= ?ele ?role) then (if (eq FALSE (member$ ?i ?*OpAvailMoves*)) then (bind ?*OpAvailMoves* (insert$ ?*OpAvailMoves* (+ 1 (length$ ?*OpAvailMoves*)) ?i))) else (if (eq FALSE (member$ ?i ?*MyAvailMoves*)) then (bind ?*MyAvailMoves* (insert$ ?*MyAvailMoves* (+ 1 (length$ ?*MyAvailMoves*)) ?i))))) ;NorthWest (bind ?available false) (if (and (> ?x 1) (> ?y 1)) then (bind ?ele (nth$ (+ (* (- ?x 1) 8) ?y) ?*GlobalBoard*)) ;(x-1, y-1) ;(printout t ":" ?ele crlf) (if (<> ?ele 0) then (bind ?j (- ?x 2)) (bind ?k (- ?y 2)) (while (and (>= ?j 0) (>= ?k 0)) do ;j <- x-2..0, k <- y-2..0 (bind ?ele1 (nth$ (+ (* ?j 8) ?k 1) ?*GlobalBoard*)); (j, k) (if (= ?ele1 0) then (break)) (if (<> ?ele1 ?ele) then (bind ?available true)) (bind ?j (- ?j 1)) (bind ?k (- ?k 1)) ))) (if (eq ?available true) then (if (= ?ele ?role) then (if (eq FALSE (member$ ?i ?*OpAvailMoves*)) then (bind ?*OpAvailMoves* (insert$ ?*OpAvailMoves* (+ 1 (length$ ?*OpAvailMoves*)) ?i))) else (if (eq FALSE (member$ ?i ?*MyAvailMoves*)) then (bind ?*MyAvailMoves* (insert$ ?*MyAvailMoves* (+ 1 (length$ ?*MyAvailMoves*)) ?i))))) ) ; Print the final result of the game. ; (deffunction printResult () (bind ?black 0) (bind ?white 0) (loop-for-count (?i 1 64) do (bind ?ele (nth$ ?i ?*GlobalBoard*)) (if (= ?ele -1) then (bind ?black (+ ?black ?ele)) else (bind ?white (+ ?white ?ele))) ) (if (> (+ ?black ?white) 0) ;white wins then (printout t " ---- white wins " (+ ?black ?white) " discs !") else (printout t " ---- black wins " (- 0 (+ ?black ?white)) " discs !")) (printout t " (white:" ?white " black:" (- 0 ?black) ")" crlf) ) ;------------------ Strategy functions ------------------ ; ; Assoicate different weights to the available moves according to the affects of each possible move or ; the importance of each square based on the strategies. ; The maximal weight means the optimal square for placing. ; (deffunction weighMyAvailMoves (?role) ;1. Global strategy: ;(1) Limit the moves available to the opponent (bind ?*MyAvailMoveWeights* (create$ )) (loop-for-count (?i 1 (length$ ?*MyAvailMoves*)) do (bind ?oldGlobalBoard ?*GlobalBoard*) ;Protect ?*GlobalBoard* (bind ?oldMyAvailMoves ?*MyAvailMoves*) ;Protect ?*MyAvailMoves* (bind ?oldOpAvailMoves ?*OpAvailMoves*) ;Protect ?*OpAvailMoves* (bind ?*FlippingDiscs* (create$ )) ;Clear ?*OpAvailMoves* (bind ?pos (nth$ ?i ?*MyAvailMoves*)) ;Pretend to place a disc at the current available square (bind ?x (div (- ?pos 1) 8)) (bind ?y (mod (- ?pos 1) 8)) ;x, y (markFlippingDiscs ?x ?y ?role) (loop-for-count (?j 1 (length$ ?*FlippingDiscs*)) do (bind ?ele (nth$ ?j ?*FlippingDiscs*)) (bind ?*GlobalBoard* (replace$ ?*GlobalBoard* ?ele ?ele ?role)) ) ;Compute the fake available moves for myself (bind ?*MyAvailMoves* (create$ )) ;clear the old available moves (bind ?*OpAvailMoves* (create$ )) (loop-for-count (?j 1 64) do (bind ?ele (nth$ ?j ?*GlobalBoard*)) ;ele (if (= ?ele 0) then (markAvailMoves ?j ?role)) ) (bind ?*MyAvailMoveWeights* (insert$ ?*MyAvailMoveWeights* ?i (- 0 (length$ ?*OpAvailMoves*)))) ;(2) Corners have the very high priorities ;-- If the current pos is a corner, add a high weight (64) to the old weight (if (neq FALSE (member$ ?pos ?*Corners*)) then (bind ?oldWeight (nth$ ?i ?*MyAvailMoveWeights*)) (bind ?*MyAvailMoveWeights* (replace$ ?*MyAvailMoveWeights* ?i ?i (+ 64 ?oldWeight)))) ;(3) Deny the opponent access to critical squares (e.g., Corners) or poison them ;-- If the place on the current pos will enable the opponent's placing on a corner, subtract a weight (32) from the old weight (loop-for-count (?j 1 (length$ ?*Corners*)) do (bind ?corner (nth$ ?j ?*Corners*)) (if (neq FALSE (member$ ?corner ?*OpAvailMoves*)) then (bind ?oldWeight (nth$ ?i ?*MyAvailMoveWeights*)) (bind ?*MyAvailMoveWeights* (replace$ ?*MyAvailMoveWeights* ?i ?i (- ?oldWeight 32))))) ;(4) Minimize frontier discs (Flip the interior discs more than to flip outer discs??????????????????) ;-- Subtract the # of frontiers that the current place produces (bind ?frontier 0) ;2. Openning phase: ;(1) Don't grab too many discs in the early stage of the game ;-- Subtract the # of friendly discs that the current place produces (bind ?friends 0) ;(2) Avoid placing on XSquares and CSquares prematurely ;-- Subtract a large number (16) from the current weight (bind ?subtraction 0) (loop-for-count (?j 1 64) do (bind ?ele (nth$ ?j ?*GlobalBoard*)) (if (= ?ele ?role) ;friendly square then (if (eq opening ?*Phase*) then (bind ?friends (+ ?friends 1))) ;2.(1) (if (neq FALSE (member$ ?j ?*CSquares*)) then (bind ?subtraction (+ ?subtraction 16))) ;2.(2) (if (neq FALSE (member$ ?j ?*XSquares*)) then (bind ?subtraction (+ ?subtraction 16))) ;2.(2) (if (and (> (- ?j 9) 0) (= 0 (nth$ (- ?j 9) ?*GlobalBoard*))) then (bind ?frontier (+ ?frontier 1))) (if (and (> (- ?j 8) 0) (= 0 (nth$ (- ?j 8) ?*GlobalBoard*))) then (bind ?frontier (+ ?frontier 1))) (if (and (> (- ?j 7) 0) (= 0 (nth$ (- ?j 7) ?*GlobalBoard*))) then (bind ?frontier (+ ?frontier 1))) (if (and (> (- ?j 1) 0) (= 0 (nth$ (- ?j 1) ?*GlobalBoard*))) then (bind ?frontier (+ ?frontier 1))) (if (and (< (+ ?j 1) 65) (= 0 (nth$ (+ ?j 1) ?*GlobalBoard*))) then (bind ?frontier (+ ?frontier 1))) (if (and (< (+ ?j 7) 65) (= 0 (nth$ (+ ?j 7) ?*GlobalBoard*))) then (bind ?frontier (+ ?frontier 1))) (if (and (< (+ ?j 8) 65) (= 0 (nth$ (+ ?j 8) ?*GlobalBoard*))) then (bind ?frontier (+ ?frontier 1))) (if (and (< (+ ?j 9) 65) (= 0 (nth$ (+ ?j 9) ?*GlobalBoard*))) then (bind ?frontier (+ ?frontier 1))))) (bind ?oldWeight (nth$ ?i ?*MyAvailMoveWeights*)) (bind ?*MyAvailMoveWeights* (replace$ ?*MyAvailMoveWeights* ?i ?i (- ?oldWeight ?frontier ?friends ?subtraction))) (bind ?*GlobalBoard* ?oldGlobalBoard) ;Restore ?*GlobalBoard* (bind ?*MyAvailMoves* ?oldMyAvailMoves) ;Restore ?*MyAvailMoves* (bind ?*OpAvailMoves* ?oldOpAvailMoves) ;Restore ?*OpAvailMoves* ) ;3. Midgame phase: ;(1) Avoid unbalanced edges, otherwise, balance them. ;(2) Consider the consequence of initiating edge play. Be careful with CSquares and XSquares ;(3) Play into regious with odd number of spaces ;4. Endgame phase: ;(1) Count the results of moves (by considering possibilities). ) ; Find the optimal move for myself (the program). ; (deffunction findOptimalMove (?role) (weighMyAvailMoves ?role) (bind ?maxWeight (nth$ 1 ?*MyAvailMoveWeights*)) (loop-for-count (?i 2 (length$ ?*MyAvailMoveWeights*)) do (bind ?weight (nth$ ?i ?*MyAvailMoveWeights*)) (if (> ?weight ?maxWeight) then (bind ?maxWeight ?weight)) ) (bind ?maxWeightedMove (nth$ (member$ ?maxWeight ?*MyAvailMoveWeights*) ?*MyAvailMoves*)) ) ; ;============== Rules =============== ; ;----------- Rules for Program Control ----------- ; ; Input and set the role (white:1 or black:-1) of the program robot ; (defrule setRole "Set the role of this program" (declare (salience 300)) => (printout t "Please choose the role for this computer:" crlf) (printout t "1. White (O); -1. Black (X)" crlf ">") (assert (role (read t))) ) ; Check if the game is over ; (defrule gameOver (declare (salience 40)) (role ?role) ?turn <- (turn ?turnNo) ?board <- (board $?) => ;Check if the game is over (if (and (= 0 (length$ ?*MyAvailMoves*)) (= 0 (length$ ?*OpAvailMoves*))) then (printout t crlf " --- ! Game Over ! ---" crlf) (printResult) ;self-defined function: print the final result of the game (retract ?board)) ) ;----------- Rules for Board ----------- ; ; Initialize the board: ; '1' for 'white', '-1' for 'black', and '0' for 'empty'; ; (4,4) and (5,5) are 'whites', and (4,5) and (5,4) are 'blacks'. ; (defrule initBoard "Initialized the Board" (declare (salience 200)) => (assert (board 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 0 0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)) (assert (turn -1)) ;Black will always play the first move (assert (printstarting true)) ) ; In order to keep the inconsistence between the fact "board" and the global variable ?*GlobalBoard*, ; every time when the "board" is changed, update ?*GlobalBoard* accordingly. ; Meanwhile compute the phase of the game. ; (defrule copyBoard "Copy the current Board layout to the ?*GlobalBoard*; Compute the phase of the game" (declare (salience 200)) (board $?board) => (bind ?*GlobalBoard* $?board) (computePhase) ) ; Pretty-print the Board. To start printing, use the fact "(assert (printstarting true))". ; (defrule printBoard "Pretty-print the Board" (declare (salience 100)) ?printstarting <- (printstarting true) (turn ?turn) => (retract ?printstarting) (printout t " ") (loop-for-count (?i 1 8) do (printout t ?i)) (bind ?black 0) (bind ?white 0) ;Compute the count of black discs and white discs (loop-for-count (?i 1 64) do (bind ?ele (nth$ ?i ?*GlobalBoard*)) (if (= ?ele -1) then (bind ?black (- ?black ?ele)) else (bind ?white (+ ?white ?ele)))) (if (<> 0 (length$ ?*NewMove*)) then (if (= ?turn 1) then (printout t " - black move (x:" (nth 1 ?*NewMove*) ", y:" (nth 2 ?*NewMove*) ") -") else (printout t " - white move (x:" (nth 1 ?*NewMove*) ", y:" (nth 2 ?*NewMove*) ") -")) (printout t " black:" ?black ", white:" ?white crlf) else (printout t " black:" ?black ", white:" ?white crlf)) (bind ?*NewMove* (create$)) (loop-for-count (?i 1 64) do (bind ?ele (nth$ ?i ?*GlobalBoard*)) (if (= 1 (mod ?i 8)) then (printout t " " (+ 1 (div ?i 8)) " ") ) (if (= ?ele 1) then (printout t "O") else (if (= ?ele -1) then (printout t "X") else (printout t "-")) ) (if (= 0 (mod ?i 8)) then (printout t " " (div ?i 8) crlf) ) ) (printout t crlf) ) ;----------- Rules for Moves ----------- ; ; Place & Flip -- 1 ; Find and mark the discs that need to be flipped ; (defrule compFlippingDiscs (declare (salience 70)) (turn ?turnNo) (NewMove ?x ?y) => (bind ?*FlippingDiscs* (create$ )) ;clear the old flipping discs (markFlippingDiscs (- ?x 1) (- ?y 1) ?turnNo) ;function "markAvailMoves" ) ; Place & Flip -- 2 ; (defrule placeFlipDiscs (declare (salience 60)) ?turn <- (turn ?turnNo) ?NewMove <- (NewMove ?x ?y) ?board <- (board $?first ?middle $?last) => (if (= 0 (length$ ?*FlippingDiscs*)) then (retract ?NewMove) (retract ?turn) (assert (turn (- 0 ?turnNo))) (assert (printstarting true)) (bind ?*NewMove* (create$ ?x ?y)) ;bind "x" and "y" of the current move to ?*NewMove* else (bind ?pos (nth 1 ?*FlippingDiscs*)) (if (= (length$ $?first) (- ?pos 1)) ;now, the '?middle' is the element that needs to be flipped then (bind ?*FlippingDiscs* (rest$ ?*FlippingDiscs*)) (retract ?board) (if (= ?middle 0) then (assert (board $?first ?turnNo $?last)) else (assert (board $?first (- 0 ?middle) $?last))))) ) ; Ask for and accept a move of the human opponent ; (defrule humanMove "Ask for and accept a move of the human opponent" (declare (salience 80)) (role ?role) ?turn <- (turn ?turnNo) (or (and (role 1) (turn -1)) (and (role -1) (turn 1))) ;Only when 'role' and 'turn' are different => (bind ?*MyAvailMoves* (create$ )) ;clear the old available moves (bind ?*OpAvailMoves* (create$ )) (bind ?returned false) (loop-for-count (?i 1 64) do (bind ?ele (nth$ ?i ?*GlobalBoard*)) ;ele (if (= ?ele 0) then (markAvailMoves ?i ?role))) ;function "markAvailMoves" (bind ?lenOp (length$ ?*OpAvailMoves*)) (bind ?lenMy (length$ ?*MyAvailMoves*)) ;Check if the move should be forced (if (or (= 1 ?lenMy) (= 1 ?lenOp)) then (if (or (and (= ?role -1) (= ?turnNo -1) (= 1 ?lenMy)) (and (= ?role 1) (= ?turnNo -1) (= 1 ?lenOp))) then (bind ?ele 0) (if (and (= ?role -1) (= ?turnNo -1) (= 1 ?lenMy)) then (bind ?ele (nth$ 1 ?*MyAvailMoves*)) else (bind ?ele (nth$ 1 ?*OpAvailMoves*))) (bind ?x (div (- ?ele 1) 8)) (bind ?y (mod (- ?ele 1) 8)) ;x, y (printout t crlf " --- black move is forced (x:" (+ 1 ?x) ", y:" (+ 1 ?y) ")" crlf) (assert (NewMove (+ 1 ?x) (+ 1 ?y))) (bind ?returned true)) (if (or (and (= ?role 1) (= ?turnNo 1) (= 1 ?lenMy)) (and (= ?role -1) (= ?turnNo 1) (= 1 ?lenOp))) then (bind ?ele 0) (if (and (= ?role 1) (= ?turnNo 1) (= 1 ?lenMy)) then (bind ?ele (nth$ 1 ?*MyAvailMoves*)) else (bind ?ele (nth$ 1 ?*OpAvailMoves*))) (bind ?x (div (- ?ele 1) 8)) (bind ?y (mod (- ?ele 1) 8)) ;x, y (printout t crlf " --- white move is forced (x:" (+ 1 ?x) ", y:" (+ 1 ?y) ")" crlf) (assert (NewMove (+ 1 ?x) (+ 1 ?y))) (bind ?returned true))) ;Check if the move should be passed (if (or (<> 0 ?lenMy) (<> 0 ?lenOp)) then (if (or (and (= ?role -1) (= ?turnNo -1) (= 0 ?lenMy)) (and (= ?role 1) (= ?turnNo -1) (= 0 ?lenOp))) then (printout t crlf " --- black move is passed" crlf) (retract ?turn) ;Change the turn (assert (turn (- 0 ?turnNo))) (bind ?returned true)) (if (or (and (= ?role 1) (= ?turnNo 1) (= 0 ?lenMy)) (and (= ?role -1) (= ?turnNo 1) (= 0 ?lenOp))) then (printout t crlf " --- white move is passed" crlf) (retract ?turn) ;Change the turn (assert (turn (- 0 ?turnNo))) (bind ?returned true))) (if (and (<> ?lenOp 0) (eq false ?returned)) then (bind ?invalidinput true) (while (eq ?invalidinput true) do (if (= ?role 1) then (printout t "Input for black x: ") else (printout t "Input for white x: ")) (bind ?x (read t)) (if (= ?role 1) then (printout t "Input for black y: ") else (printout t "Input for white y: ")) (bind ?y (read t)) (if (neq FALSE (member$ (+ (* (- ?x 1) 8) ?y) ?*OpAvailMoves*)) then (assert (NewMove ?x ?y)) (bind ?invalidinput false) else (printout t "Input invalid, please input again !" crlf)))) ) ; Pick up an optimal move from the ?*MyAvailMoves* for the computer (myself) ; (defrule myMove (declare (salience 50)) (role ?role) ?turn <- (turn ?turnNo) (or (and (role 1) (turn 1)) (and (role -1) (turn -1))) ;Only when 'role' and 'turn' are same => (bind ?*MyAvailMoves* (create$ )) ;clear the old available moves (bind ?*OpAvailMoves* (create$ )) (bind ?returned false) (loop-for-count (?i 1 64) do (bind ?ele (nth$ ?i ?*GlobalBoard*)) ;ele (if (= ?ele 0) then (markAvailMoves ?i ?role))) ;function "markAvailMoves" (bind ?lenOp (length$ ?*OpAvailMoves*)) (bind ?lenMy (length$ ?*MyAvailMoves*)) ;Check if the move should be forced (if (or (= 1 ?lenMy) (= 1 ?lenOp)) then (if (or (and (= ?role -1) (= ?turnNo -1) (= 1 ?lenMy)) (and (= ?role 1) (= ?turnNo -1) (= 1 ?lenOp))) then (bind ?ele 0) (if (and (= ?role -1) (= ?turnNo -1) (= 1 ?lenMy)) then (bind ?ele (nth$ 1 ?*MyAvailMoves*)) else (bind ?ele (nth$ 1 ?*OpAvailMoves*))) (bind ?x (div (- ?ele 1) 8)) (bind ?y (mod (- ?ele 1) 8)) ;x, y (printout t crlf " --- black move is forced (x:" (+ 1 ?x) ", y:" (+ 1 ?y) ")" crlf) (assert (NewMove (+ 1 ?x) (+ 1 ?y))) (bind ?returned true)) (if (or (and (= ?role 1) (= ?turnNo 1) (= 1 ?lenMy)) (and (= ?role -1) (= ?turnNo 1) (= 1 ?lenOp))) then (bind ?ele 0) (if (and (= ?role 1) (= ?turnNo 1) (= 1 ?lenMy)) then (bind ?ele (nth$ 1 ?*MyAvailMoves*)) else (bind ?ele (nth$ 1 ?*OpAvailMoves*))) (bind ?x (div (- ?ele 1) 8)) (bind ?y (mod (- ?ele 1) 8)) ;x, y (printout t crlf " --- white move is forced (x:" (+ 1 ?x) ", y:" (+ 1 ?y) ")" crlf) (assert (NewMove (+ 1 ?x) (+ 1 ?y))) (bind ?returned true))) ;Check if the move should be passed (if (or (<> 0 ?lenMy) (<> 0 ?lenOp)) then (if (or (and (= ?role -1) (= ?turnNo -1) (= 0 ?lenMy)) (and (= ?role 1) (= ?turnNo -1) (= 0 ?lenOp))) then (printout t crlf " --- black move is passed" crlf) (retract ?turn) ;Change the turn (assert (turn (- 0 ?turnNo))) (bind ?returned true)) (if (or (and (= ?role 1) (= ?turnNo 1) (= 0 ?lenMy)) (and (= ?role -1) (= ?turnNo 1) (= 0 ?lenOp))) then (printout t crlf " --- white move is passed" crlf) (retract ?turn) ;Change the turn (assert (turn (- 0 ?turnNo))) (bind ?returned true))) (if (and (<> ?lenMy 0) (eq false ?returned)) then (bind ?i (findOptimalMove ?role)) ;Call self-defined strategy functions to pickup the optimal move for myself (bind ?x (div (- ?i 1) 8)) (bind ?y (mod (- ?i 1) 8)) ;x, y (assert (NewMove (+ 1 ?x) (+ 1 ?y)))) )