Othello Game Programs (human to human) 1 The rule of the game Othello is played on a 8-by-8 board, which is initially set up with four pieces in the center. Two players, black and white, alternate turns, with black playing first. Each piece must be placed so that it brackets one or more opponent pieces.The intervening white pieces are flipped over to black, and vice verse. Initializing board (1) (defconstant all-directs '(-11 -10 -9 -1 1 9 10 11)) ALL-DIRECTS (defconstant empty 0) EMPTY (defconstant black 1) BLACK (defconstant white 2) WHITE (defconstant outer 3) OUTER (deftype piece () `(integer ,empty ,outer)) PIECE (defun name-of (piece) (char ".@0?" piece)) NAME-OF 2 (defun opponent (player) (if (eql player black) white black)) OPPONENT (defconstant all-squares (deftype board () '(simple-array piece (100))) '(1 2 3 4 5 6 7 8 11 12 13 14 15 16 17 18 BOARD 21 22 23 24 25 26 27 28 31 32 33 34 35 36 37 38 (defun copy-board (board) (copy-seq board)) 41 42 43 44 45 46 47 48 51 52 53 54 55 56 57 58 61 62 63 64 65 66 67 68 COPY-BOARD 71 72 73 74 75 76 77 78 (defconstant all-squares 81 82 83 84 85 86 87 88 )) (loop for i from 11 to 88 when (<= 1 (mod i 10) 8) collect i)) ALL-SQUARES (defun count-difference (player board) (- (count player board) (count (opponent player) board))) COUNT-DIFFERENCE 3 (defun initial-board () (let ((board (make-array 100 :element-type 'piece :initial-element outer ))) (dolist (square all-squares) (setf (bref board square) empty)) (setf (aref board 44) white (aref board 45) black (aref board 54) black (aref board 55) white) board)) INITIAL-BOARD (defun print-board (board) (format t "~2& 1 2 3 4 5 6 7 8 [~c=~2a ~c=~2a (~@d)]" (name-of black) (count black board) (name-of white) (count white board) (count-difference black board)) (loop for row from 1 to 8 do (format t "~& ~d " (* 10 row)) (loop for col from 1 to 8 for piece = (aref board (+ col (* 10 row))) do (format t "~c " (name-of piece)))) (format t "~2&")) 4 (write (initial-board) :array t) #(3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 3 3 0 0 0 0 0 0 0 0 3 3 0 0 0 0 0 0 0 0 3 3 0 0 0 2 1 0 0 0 3 3 0 0 0 1 2 0 0 0 3 3 0 0 0 0 0 0 0 0 3 3 0 0 0 0 0 0 0 0 3 3 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3) #(3 3 3 3 3 3 3 3 3 3 ...) (print-board (initial-board)) 1 2 3 4 5 6 7 8 [@=2 0=2 (0)] 10 . . . . . . . . 20 . . . . . . . . 30 . . . . . . . . 40 . . . 0 @ . . . 50 . . . @ 0 . . . 60 . . . . . . . . 70 . . . . . . . . 80 . . . . . . . . NIL 5 (defun valid-p (move) (and (integerp move) (<= 11 move 88) (<= 1 (mod move 10) 8))) VALID-P (valid-p 60) NIL (valid-p 43) (defun legal-p (move player board) T (and (eql (aref board move) empty) (some #'(lambda (dir) (would-flip? move player board dir)) all-directions))) LEGAL-P (defun would-flip? (move player board dir) (let ((c (+ move dir))) (and (eql (aref board c) (opponent player)) (find-bracketing-piece (+ c dir) player board dir)))) WOULD-FLIP? (defun find-bracketing-piece (square player board dir) (cond ((eql (aref board square) player) square) ((eql (aref board square) (opponent player)) (find-bracketing-piece (+ square dir) player board dir)) (t nil))) FIND-BRACKETING-PIECE (legal-p 43 black (initial-board)) 45 (legal-p 42 black (initial-board)) NIL 6 (defun make-move (move player board) (setf (aref board move) player) (dolist (dir all-directions) (make-flips move player board dir)) board) MAKE-MOVE (defun make-flips (move player board dir) (let ((bracketer (would-flip? move player board dir))) (when bracketer (loop for c from (+ move dir) by dir until (eql c bracketer) do (setf (aref board c) player))))) MAKE-FLIPS (print-board (make-move 56 black (initial-board))) 1 2 3 4 5 6 7 8 [@=4 0=1 (+3)] 10 / / / / / / / / 20 / / / / / / / / (make-move 56 black (initial-board)) 30 / / / / / / / / #(3 0 0 3 3 0 0 3) 40 / / / 0 @ / / / 50 / / / @ @ @ / / 60 / / / / / / / / 3 0 0 0 3 0 0 0 3 0 0 0 3 3 1 3 3 3 1 3 3 0 1 0 3 0 0 0 3 0 0 0 3 0 3 0 3 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 3 0 3 0 3 0 0 0 3 0 0 0 3 0 0 0 3 3 2 3 3 3 1 3 3 70 / / / / / / / / 80 / / / / / / / / NIL 7 0 0 0 3 0 0 0 3 0 0 0 3 (defun othello (bl-strategy wh-strategy &optional (print t)) (let ((board (initial-board))) (loop for player = black then (next-to-play board player print) for strategy = (if (eql player black) bl-strategy wh-strategy) until (null player) do (get-move strategy player board print)) (when print (format t "~&The game is over. Final result:") (print-board board)) (count-difference black board))) OTHELLO 8 (defun get-move (strategy player board print) (when print (print-board board)) (let ((move (funcall strategy player (copy-board board)))) (cond ((eq move 0) (progn (format t "~& abort ") (abort))) ((and (valid-p move) (legal-p move player board)) (when print (format t "~&~c moves to ~d." (name-of player) move)) (make-move move player board)) (t (warn "Illegal move: ~d" move) (get-move strategy player board print))))) GET-MOVE 9 (defun next-to-play (board previous-player print) (let ((opp (opponent previous-player))) (cond ((any-legal-move? opp board) opp) ((any-legal-move? previous-player board) (when print (format t "~&~c has no moves and must pass." (name-of opp))) previous-player) (t nil)))) NEXT-TO-PLAY (next-to-play (initial-board) white t) 1 (defun any-legal-move? (player board) (some #'(lambda (move) (legal-p move player board)) all-squares)) ANY-LEGAL-MOVE? (any-legal-move? black (initial-board)) 54 (defun human (player board) (declare (ignore board)) (format t "~&~c to move: " (name-of player)) (first (read))) HUMAN (human black (initial-board)) @ to move: (56) (56) 10 Two people play against each other @ to move: (56) @ moves to 56. (othello #'human #'human)) 1 2 3 4 5 6 7 8 [@=2 0=2 (0)] 10 / / / / / / / / 50 / / / @ @ @ / / 60 / / / / / / / / 60 / / / / / / / / 70 / / / / / / / / 70 / / / / / / / / 80 / / / / / / / / 80 / / / / / / / / @ to move: (57) 0 to move: (64) ;;; Warning: Illegal move: 57 40 / / / 0 @ / / / 50 / / / @ 0 / / / 60 / / / / / / / / 70 / / / / / / / / 80 / / / / / / / / 0=3 40 / / / 0 @ / / / 50 / / / @ 0 / / / 30 / / / / / / / / [@=3 (+3)] 30 / / / / / / / / 40 / / / 0 @ / / / 20 / / / / / / / / 0=1 20 / / / / / / / / 30 / / / / / / / / 10 / / / / / / / / [@=4 10 / / / / / / / / 20 / / / / / / / / 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 [@=2 0=2 (0)] 0 moves to 64. 1 2 3 4 5 6 7 8 10 / / / / / / / / 20 / / / / / / / / 30 / / / / / / / / 40 / / / 0 @ / / / 50 / / / 0 @ @ / / 60 / / / 0 / / / / 70 / / / / / / / / 80 / / / / / / / / 11 (0)] Exercise Problems If you have time, try to do the following exercise problems. 1. Understand examples in lecture notes. 2. Can you make a random strategy function so that a human plays again computer that uses the random strategy. 3. Can you make a (8 x 8)Tic Tac Toe game that two human players can play. 12