라이프로그


Lisp - Tic-Tac-Toe by Shocky

 

(defConstant One 1)              ;; human
(defConstant TheOther 10)        ;; computer

(defvar *Opponent* one)
(defvar *Computer* TheOther)

(defvar *Triplets*
  '((1 2 3) (4 5 6) (7 8 9);;Horizontal
    (1 4 7) (2 5 8) (3 6 9);;Vertical
    (1 5 9) (3 5 7)));;Diagonal


(defconstant Three 3)      ;; three in a row
(defconstant Nine 9)       ;; There're nine cells.


(defun makeBoard ()
   (list 'Board 0 0 0 0 0 0 0 0 0))

 

(defun convert-to-letter (v)
   (cond ((equal v One) "O")
         ((equal v TheOther) "X")
         (t " ")))

(defun print-row (x y z)
   (format t "~&     ~A | ~A| ~A"
     (convert-to-letter x)
     (convert-to-letter y)
     (convert-to-letter z)))

(defun printBoard (board)
   (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 "~%~%"))


;;
;;  Set the player's move
;;

(defun makeMove (Player Pos Board)
   (setf (nth Pos Board) Player)
   Board)

;;> (setf MyBoard (makeBoard))
;;(BOARD 0 0 0 0 0 0 0 ...)
;;> (makeMove *Opponent* 3 MyBoard)
;;(BOARD 0 0 1 0 0 0 0 ...)
;;> (makeMove *Computer* 5 MyBoard)
;;(BOARD 0 0 1 0 10 0 0 ...)
;;> (printBoard MyBoard)
;;       |  | O
;; ----------------
;;       | X| 
;; ----------------
;;       |  | 

(defun sumTriplet (Board Triplet)
   (+ (nth (first Triplet) Board)
      (nth (second Triplet) Board)
      (nth (third Triplet) Board)))

;;
;;>(sumTiplet MyBoard '(3 5 7))
;;

(defun computeSums (Board)
   (mapcar #'(lambda (Triplet)
               (sumTriplet Board Triplet))
     *Triplets*))

;;> (computeSums MyBoard)
;;(1 10 0 0 10 1 10 11)

(defun winnerP (Board)
   (let ((Sums (computeSums Board)))
      (or (member (* 3 *Computer*) Sums)
          (member (* 3 *Opponent*) Sums))))

(defun playOneGame ()
   (if (y-or-n-p "Do you like to go first? ")
      (opponentMove (makeBoard))
      (computerMove (makeBoard))))

(defun opponentMove (Board)
   (let* ((Pos (readALegalMove Board))
          (NewBoard (makeMove *Opponent* Pos Board)))
      (printBoard NewBoard)
      (cond ((winnerP NewBoard) 'YouWin)
            ((boardFullP NewBoard) 'TieGame)
            (t (computerMove NewBoard)))))

(defun readALegalMove (Board)
   (format t "~& Your move: ")
   (let ((Pos (read)))
      (cond ((not (and (integerp Pos) (<= 1 Pos 9)))
             (format t "~& Invalid input.")
             (readALegalMove Board))
            ((not (zerop (nth Pos Board)))
             (format t "~& Already occupied.")
             (readALegalMove Board))
            (t Pos))))

(defun boardFullP (Board)
   (not (member 0 Board)))

(defun computerMove (Board)
   (let* ((BestMove (chooseBestMove Board))
          (Pos (first BestMove))
          (Strategy (second BestMove))
          (NewBoard (makeMove *Computer* Pos Board)))
      (format t "~&My move: ~S" Pos)
      (format t "~&My strategy: ~A~%" Strategy)
      (printBoard NewBoard)
      (cond ((winnerP NewBoard) 'IWin)
            ((boardFullP NewBoard) 'TieGame)
            (t (opponentMove NewBoard)))))

(defun chooseBestMove (Board)
   "1st version"
   (randomMoveStrategy Board))

(defun randomMoveStrategy (Board)
   (list (pickRandomEmptyPosition Board) "Random Move"))

(defun pickRandomEmptyPosition (Board)
   (let ((Pos (+ 1 (random 9))))
      (if (zerop (nth Pos Board))
         Pos
         (pickRandomEmptyPosition Board))))

(defun makeThree (Board)
   (let ((Pos (winOrBlock Board (* 2 *Computer*)))) ;; 2 * 10
      (and Pos (list Pos "make three in a row"))))

(defun blockOpponentWin (Board)
   (let ((Pos (winOrBlock Board (* 2 *Opponent*)))) ;; 2 * 1
      (and Pos (list Pos "block the opponent"))))

(defun winOrBlock (Board TargetSum)
   (let ((Triplet ;; Triplet ? a specific triplet, e.g., (1 2 3)
           (find-if #'(lambda (Tri)
                        (equal (sumTriplet Board Tri) TargetSum))
             *Triplets*)))
      (when Triplet (findEmptyPosition Board Triplet))))

(defun findEmptyPosition (Board Cells) ;; Cells in a triplet, (1 2 3)
   (find-if #' (lambda (Pos) (zerop (nth Pos Board))) Cells))

(defun chooseBestMove (Board)
   "2nd version"
   (or (makeThree Board)
       (blockOpponentWin Board)
       (randomMoveStrategy Board)))


1 2 3 4 5 6 7 8 9 10 다음