;; --------------------------------------------- ;; John Paxton ;; November 10, 2007 ;; CS 436 ;; driver.l ;; --------------------------------------------- ;; This file contains the driver for the fourth ;; CS 436 programming assignment. ;; --------------------------------------------- ;; --------------------------------------------- ;; Global variables and global constants ;; --------------------------------------------- (defvar *size* 15) ;; size of gomoku board (defvar *to-win* 5) ;; number of stones in a row to produce a win (defconstant *empty* 'e) ;; constant for empty square (defconstant *black* 'b) ;; constant for black stone (defconstant *white* 'w) ;; constant for white stone ;; --------------------------------------------- ;; Driver ;; --------------------------------------------- ;; This is the referee function that allows a ;; game of gomoku to be played. ;; --------------------------------------------- (defun driver () (do* ;; ---------- local loop variables ;; ;; board - an n by n matrix ;; board-copy - a copy of the board ;; whose-move - the player to next move ;; number-moves - the number of moves made in the game so far ;; move - the current move in the form '(x y) ( (board (make-array `(,*size* ,*size*) :initial-element *empty*)) (board-copy (make-array `(,*size* ,*size*) :initial-element *empty*) (copy-board board-copy board)) (whose-move *white* (other-player whose-move)) (number-moves 0 (+ 1 number-moves)) (game-over nil) move ) ;; exit when the game is over or the board is filled ((or game-over (= number-moves (* *size* *size*))) (format t "Number of moves = ~a~%" number-moves) (print-board board) ) (if (equal whose-move *white*) (setf move (time (white-get-move board-copy))) (setf move (time (black-get-move board-copy))) ) (format t "~a plays at ~a~2%" whose-move move) (cond ;; check to see if the play coordinates are legal ((or (not (legal-p *size* (first move))) (not (legal-p *size* (second move)))) (format t "~a has played illegally, ~a wins!~%" whose-move (other-player whose-move)) (setf game-over t) ) ;; ensure that the square is not already occupied ((not (equal (aref board (first move) (second move)) *empty*)) (format t "~a has played in an occupied square, ~a wins!~%" whose-move (other-player whose-move)) (setf game-over t) ) (t (setf (aref board (first move) (second move)) whose-move) ;; check to see if the game has been won (when (five-in-a-row-p board (first move) (second move)) (format t "~a wins!~%" whose-move) (setf game-over t) ) ) ) ) ) ;; --------------------------------------------- ;; copy-board ;; --------------------------------------------- ;; board-copy: a copy of the board ;; board: the actual board ;; --------------------------------------------- ;; Make a copy of the board. ;; --------------------------------------------- (defun copy-board (board-copy board) (dotimes (i *size* board-copy) (dotimes (j *size*) (setf (aref board-copy i j) (aref board i j)) ) ) ) ;; --------------------------------------------- ;; print-board ;; --------------------------------------------- ;; board: the gomoku board ;; --------------------------------------------- ;; Print a readable text-based depiction of the ;; current game situation. ;; --------------------------------------------- (defun print-board (board) (format t " ") (dotimes (i *size*) (format t "~3d " i) ) (format t "~%") (dotimes (i *size*) (print-separator) (format t "~2d " i) (dotimes (j *size*) (format t "| ~a " (aref board i j)) ) (format t "|~%") ) (print-separator) ) ;; --------------------------------------------- ;; print-separator ;; --------------------------------------------- ;; Print a separator around each row of the game ;; board to make it look nice. ;; --------------------------------------------- (defun print-separator () (format t " ") (dotimes (i *size*) (format t "+---") ) (format t "+~%") ) ;; --------------------------------------------- ;; other-player ;; --------------------------------------------- ;; whose-move: the player to move ;; --------------------------------------------- ;; Return the other player ;; --------------------------------------------- (defun other-player (whose-move) (if (equal whose-move *white*) *black* *white* ) ) ;; --------------------------------------------- ;; five-in-a-row-p ;; --------------------------------------------- ;; board: an n by n matrix representing the current go board ;; x: the x position of the last stone played ;; y: the y position of the last stone played ;; --------------------------------------------- ;; Return true if the last stone played produces ;; a vertical, horizontal or diagonal line of 5 ;; or more stones in a row. ;; --------------------------------------------- (defun five-in-a-row-p (board x y) (or (five-aux-p board x y 0 1) ;; up-down (five-aux-p board x y 1 0) ;; right-left (five-aux-p board x y 1 1) ;; diagonal 1 (five-aux-p board x y 1 -1) ;; diagonal 2 ) ) ;; --------------------------------------------- ;; five-aux-p ;; --------------------------------------------- ;; board: an n by n matrix representing the current go board ;; x: x position of last stone played ;; y: y position of last stone played ;; x-inc: how to change x ;; y-inc: how to change y ;; --------------------------------------------- ;; Returns t if the number of like colored stones in ;; a single line are greater than or equal to *to-win* ;; --------------------------------------------- (defun five-aux-p (board x y x-inc y-inc) (>= (+ 1 (count-stones (aref board x y) board x y x-inc y-inc) (count-stones (aref board x y) board x y (- x-inc) (- y-inc)) ) *to-win*) ) ;; --------------------------------------------- ;; count-stones ;; --------------------------------------------- ;; color: the color of the last stone played ;; board: an n by n matrix representing the current go board ;; x: the last x position checked ;; y: the last y position checked ;; x-inc: how to change x ;; y-inc: how to change y ;; result: the number of like colored stones in a line ;; --------------------------------------------- ;; Return the number of stones in a line that match "color" ;; --------------------------------------------- (defun count-stones (color board x y x-inc y-inc &optional (result 0)) (setf x (+ x x-inc)) (setf y (+ y y-inc)) (if (and (legal-p (array-dimension board 0) x) (legal-p (array-dimension board 1) y) (equal (aref board x y) color)) (count-stones color board x y x-inc y-inc (+ result 1)) result ) ) ;; --------------------------------------------- ;; legal-p ;; --------------------------------------------- ;; max-value: the largest legal value ;; value: the value to check ;; --------------------------------------------- ;; Return true if 0 <= value < max-value ;; --------------------------------------------- (defun legal-p (max-value value) (and (>= value 0) (< value max-value)) )