Created
July 23, 2020 04:34
-
-
Save leejaycoke/000034a03f6fc52a7de700f3a73e0720 to your computer and use it in GitHub Desktop.
Tic-Tac-Toc Common Lisp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; 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