我正在做一個簡單的CLI tic-tac-toe遊戲,它使用一個使用LISP的alpha-beta修剪的negamax算法的AI,我正在人工智能如何實現其動作的問題。它不是完成它應該的單一動作,而是完全地完成遊戲,所以遊戲只有最後兩步。我已經運行了它(步驟),它看起來像問題是,在negamax函數的(when(> value bestValue))塊中設置了bestPath變量,即使它說該塊沒有被執行爲。而且,它設置的值並不是正確的值,如果它適合設置它的話。有什麼建議麼?這是我的代碼。用lisp實現的井字遊戲正在完成遊戲而不是一個動作
;
; Prints an ASCII tic tac toe board
;
(defun print-board (board)
(format t "~% ~d | ~d | ~d 0 | 1 | 2~% --------- ---------~% ~d | ~d | ~d 3 | 4 | 5~% --------- ---------~% ~d | ~d | ~d 6 | 7 | 8~%~%"
(or (nth 0 board) ".") (or (nth 1 board) ".") (or (nth 2 board) ".")
(or (nth 3 board) ".") (or (nth 4 board) ".") (or (nth 5 board) ".")
(or (nth 6 board) ".") (or (nth 7 board) ".") (or (nth 8 board) ".")))
;
; Returns the symbol representing the other player
;
(defun opposite (player)
(if (eq player 'x) 'o 'x))
;
; Checks if the player won
;
(defun won-p (board player)
(or (and (eq (nth 0 board) player)
(eq (nth 1 board) player)
(eq (nth 2 board) player))
(and (eq (nth 3 board) player)
(eq (nth 4 board) player)
(eq (nth 5 board) player))
(and (eq (nth 6 board) player)
(eq (nth 7 board) player)
(eq (nth 8 board) player))
(and (eq (nth 0 board) player)
(eq (nth 3 board) player)
(eq (nth 6 board) player))
(and (eq (nth 1 board) player)
(eq (nth 4 board) player)
(eq (nth 7 board) player))
(and (eq (nth 2 board) player)
(eq (nth 5 board) player)
(eq (nth 8 board) player))
(and (eq (nth 0 board) player)
(eq (nth 4 board) player)
(eq (nth 8 board) player))
(and (eq (nth 2 board) player)
(eq (nth 4 board) player)
(eq (nth 6 board) player))))
;
; Checks if neither player won and there are no valid moves
;
(defun draw-p (board)
(and (not (won-p board 'o))
(not (won-p board 'x))
(not (member nil board))))
;
; Places a token at the desired position unless
; it is already occupied
;
(defun make-move (board player move)
(unless (nth move board)
(let ((boardCopy (copy-list board)))
(setf (nth move boardCopy) player)
boardCopy)))
;
; Starts a human v human game of tic tac toe
;
(defun play()
(setf currentPlayer 'x)
(setf currentBoard (list nil nil nil nil nil nil nil nil nil))
(print-board currentBoard)
(do()
((or (won-p currentBoard 'x)
(won-p currentBoard 'o)
(draw-p currentBoard))
(opposite currentPlayer))
(format t "~%Enter move for ~a's: " currentPlayer)
(setf move (read))
(do()
((setf nextBoard (make-move currentBoard currentPlayer move)))
(format t "~%Illegal move. Try again: ")
(setf move (read)))
(setf currentBoard nextBoard)
(print-board currentBoard)
(if (won-p currentBoard currentPlayer)
(format t "~%Player ~a wins!" currentPlayer))
(if (draw-p currentBoard)
(format t "~%Draw!"))
(setf currentPlayer (opposite currentPlayer))))
這裏是AI的代碼。
;
; Evaluates the heuristic value of the board position
; from the viewpoint of the player
;
(defun evaluate (board player depth)
(cond ((won-p board player) (- 10 depth))
((won-p board (opposite player)) (+ -10 depth))
(t 0)))
;
; Generates all possible legal moves from the current position
;
(defun generate-moves (board player)
(loop for move from 0 to 8
unless (nth move board)
collect (make-move board player move)))
;
; Checks if the algorithm has searched deep enough into the tree.
;
(defun deep-enough (board player)
(or (won-p board player)
(won-p board (opposite player))
(draw-p board)))
;
; Algorithm for deciding which move to choose
;
(defun negamax(board player depth)
(cond ((deep-enough board player)
(cons (evaluate board player depth) board))
(t (setq bestValue -10)
(setq bestPath nil)
(setq successors (generate-moves board player))
(loop for successor in successors
do
(let* ((result (negamax successor (opposite player) (+ depth 1)))
(value (- (first result))))
(when (> value bestValue)
(setq bestValue value)
(setq bestPath successor))))
(cons bestValue bestPath))))
;
; Starts a game of tic-tac-toe with the computer
;
(defun play-ai()
(setq currentPlayer 'x)
(setq currentBoard (list nil nil nil nil nil nil nil nil nil))
(print-board currentBoard)
(do()
((or (won-p currentBoard 'x)
(won-p currentBoard 'o)
(draw-p currentBoard))
(opposite currentPlayer))
(format t "~%Enter move for ~a's: " currentPlayer)
(cond ((eq currentPlayer 'x)
(setf move (read))
(do()
((setf nextBoard (make-move currentBoard currentPlayer move)))
(format t "~%Illegal move. Try again: ")
(setf move (read)))
(setf currentBoard nextBoard)
(print-board currentBoard)
(if (won-p currentBoard currentPlayer)
(format t "~%Player ~a wins!" currentPlayer))
(if (draw-p currentBoard)
(format t "~%Draw!"))
(setf currentPlayer (opposite currentPlayer)))
(t (setq currentBoard (rest (negamax currentBoard currentPlayer 1)))
(write-line "")
(print-board currentBoard)
(if (won-p currentBoard currentPlayer)
(format t "~%Player ~a wins!" currentPlayer))
(if (draw-p currentBoard)
(format t "~%Draw!"))
(setf currentPlayer (opposite currentPlayer))))))
在遞歸函數中使用全局變量通常是不正確的,因爲遞歸調用會覆蓋調用者中使用的值。 – Barmar
PLAY,NEGAMAX和PLAY-AI中有很多未定義的變量。 –