Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leejaycoke/000034a03f6fc52a7de700f3a73e0720 to your computer and use it in GitHub Desktop.
Save leejaycoke/000034a03f6fc52a7de700f3a73e0720 to your computer and use it in GitHub Desktop.
Tic-Tac-Toc Common Lisp
;; 10년전에 만든거네..ㄷㄷ
;;
;; AI Programming: Tic-Tac-Toc
;;
;; DATE: 2010/06/03
;; 이주현
;;
(defconstant One 1) ;; Me
(defconstant TheOther 10) ;; Computer
(defvar *Opponent* One)
(defvar *Computer* TheOther)
(defvar *Triplets*
'((1 2 3) (4 5 6) (7 8 9)
(1 4 7) (2 5 8) (3 6 9)
(1 5 9) (3 5 7)))
;;
;; Initialization: Creating a board
;;
(defun make-board ()
"Creating a new board"
(list 'Board 0 0 0 0 0 0 0 0 0))
;;
;; Printing out the board
;;
(defun convert-to-letter (v)
"converting a number to a letter"
(cond ((equal v One) "O") ;; Me
((equal v TheOther) "X") ;; Computer
(t " ")))
(defun print-row (x y z)
"Printing out a row"
(format t "~& | ~A | ~A | ~A | "
(convert-to-letter x)
(convert-to-letter y)
(convert-to-letter z)))
(defun print-board (board)
"Printing out a board"
(format t "~%~%")
(format t "~& ───────")
(print-row (nth 1 board) (nth 2 board) (nth 3 board))
(format t "~& ───────")
(print-row (nth 4 board) (nth 5 board) (nth 6 board))
(format t "~& ───────")
(print-row (nth 7 board) (nth 8 board) (nth 9 board))
(format t "~& ───────")
(format t "~%~%"))
;;
;; Set the player's move
;;
(defun make-move (Player Pos Board)
"1 or 10 depending on who's moving"
(setf (nth Pos Board) Player)
Board)
;;
;; To win the game, make three-in-a-row
;; global variable: *Triplets"
;;
(defun sum-triplet (Board Triplet)
"returning the sum of the numbers in the board positions"
(+ (nth (first Triplet) Board)
(nth (second Triplet) Board)
(nth (third Triplet) Board)))
(defun compute-sums (Board)
"returning a list of all eight sums"
(mapcar #'(lambda (Triplet) (sum-triplet Board Triplet))
*Triplets*))
(defun winner-or-not (Board)
"Checking out if there is a winner"
(let ((Sums (compute-sums Board)))
(or (member (* 3 *Computer*) Sums)
(member (* 3 *Opponent*) Sums))))
;;
;;Playing the game: Let's start
;;
(defun play-one-game ()
"Playing our game"
(if (y-or-n-p "Do You like to go first? ")
(opponent-move (make-board)) ;; human first
(computer-move (make-board)))) ;; Computer first
;;
;; Human move
;;
(defun opponent-move (Board)
"asking the opponent to type in a move and
checking the legal move"
(let* ((Pos (read-a-legal-move Board))
(NewBoard (make-move *Opponent* Pos Board)))
(print-board NewBoard)
(cond ((winner-or-not NewBoard) 'YouWin)
((board-full-p NewBoard) 'TieGame)
(t (Computer-move NewBoard)))))
(defun read-a-legal-move (Board)
"checking whether it's a legal move"
(format t "~& Your move: ")
(let ((Pos (read)))
(cond ((not (and (integerp Pos) (<= 1 Pos 9)))
(format t "~& Invalid input")
(read-a-legal-move Board))
((not (zerop (nth Pos Board)))
(format t "~& Already occupied")
(read-a-legal-move Board))
(t Pos))))
(defun board-full-p (Board)
"testing if there are no more empty position left"
(not (member 0 Board)))
;;
;; Computer move
;;
(defun computer-move (Board)
"calling choose-best move"
(let* ((BestMove (choose-best-move2 Board))
(Pos (first BestMove))
(Strategy (second BestMove))
(NewBoard (make-move *Computer* Pos Board)))
(format t "~& My move: ~S" Pos)
(format t "~& My strategy: ~A~%" Strategy)
(print-board NewBoard)
(cond ((winner-or-not NewBoard) 'IWin)
((board-full-p NewBoard) 'TieGame)
(t (opponent-move NewBoard)))))
(defun choose-best-move (Board)
"1st version"
(random-move-strategy Board))
(defun random-move-strategy (Board)
"strategy: random"
(list (pick-random-empty-position Board) "Random Move"))
(defun pick-random-empty-position (Board)
"randomly select its position"
(let ((Pos (+ 1 (random 9))))
(if (zerop (nth Pos Board))
Pos
(pick-random-empty-Position Board))))
;;
;; Smarter program
;; To win the game : if there are two Xs in a row, fill in the
;; third X. To block the opponent from winning : If there are
;; two Os in a row. put an X to protect winning.
;;
(defun make-three (Board)
"If there are two Xs in a row. fill in the third X."
(let ((Pos (win-or-block Board (* 2 *Computer*))))
(and Pos (list Pos "make three in a row"))))
(defun block-opponent-win (Board)
"If there are two Os in a row. put an X there."
(let ((Pos (win-or-block Board (* 2 *Opponent*))))
(and Pos (list Pos "block the opponent"))))
(defun win-or-block (Board TargetSum)
"Checking out it there are two Xs"
(let ((Triplet
(find-if #'(lambda (Tri) (equal (sum-triplet Board Tri)
TargetSum)) *Triplets*)))
(when Triplet (find-empty-position Board Triplet))))
(defun find-empty-position (Board Cells)
"Cells in a triplet, e.g.. (1 2 3)"
(find-if #'(lambda (Pos) (zerop (nth Pos Board))) Cells))
(defun choose-best-move2 (Board)
"2nd version"
(or (make-three Board)
(block-opponent-win Board)
(random-move-strategy Board)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment