Код Common-Lisp работал нормально, теперь ошибка: Попытка получить значение несвязанной переменной `*OPPONENT*'.

Я сбит с толку. Я играю с игрой в крестики-нолики из главы 10 книги COMMON LISP: A Gentle Introduction to Symbolic Computation https://www.cs.cmu.edu/~dst/LispBook/book.pdf . Я все обработал в IDE, сохранил, а потом скомпилировал+загрузил. Запустил несколько игр без проблем. Итак, я скопировал заведомо рабочий файл и начал настраивать. Опять же, никаких проблем - все работало нормально. Однако теперь, когда я запускаю (играю в одну игру), я получаю следующую ошибку:

Ошибка: попытка получить значение несвязанной переменной '*OPPONENT**'

Я получаю ошибку как в оригинале, так и в копии. Я закрыл AllegroCL и перезагрузил компьютер, но проблема осталась после перезагрузки. Затем я обновил программу и запустил ./update.sh в ее каталоге приложений.

Наконец, я решил скопировать пример прямо из PDF в совершенно новый файл в другом каталоге, и у меня возникла та же проблема. Не знаю, что изменилось, но меня это, мягко говоря, порадовало.

(defun make-board ()
  (list 'board 0 0 0 0 0 0 0 0 0))

(defun convert-to-letter (v)
  (cond ((equal v 1) "O")
        ((equal v 10) "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 print-board (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 "~%~%"))

(defun make-move (player pos board)
  (setf (nth pos board) player)
  board)

(setf *triplets*
  '((1 2 3) (4 5 6) (7 8 9) ;Horizontal triplets.
    (1 4 7) (2 5 8) (3 6 9) ;Vertical triplets.
    (1 5 9) (3 5 7))) ;Diagonal triplets.

(defun sum-triplet (board triplet)
  (+ (nth (first triplet) board)
     (nth (second triplet) board)
     (nth (third triplet) board)))

(defun compute-sums (board)
  (mapcar #'(lambda (triplet)
              (sum-triplet board triplet))
    *triplets*))

(defun winner-p (board)
  (let ((sums (compute-sums board)))
    (or (member (* 3 *computer*) sums)
        (member (* 3 *opponent*) sums))))

(defun play-one-game ()
  (if (y-or-n-p "Would you like to go first? ")
      (opponent-move (make-board))
    (computer-move (make-board))))

(defun opponent-move (board)
  (let* ((pos (read-a-legal-move board))
         (new-board (make-move
                     *opponent*
                     pos
                     board)))
    (print-board new-board)
    (cond ((winner-p new-board)
           (format t "~&You win!"))
          ((board-full-p new-board)
           (format t "~&Tie game."))
          (t (computer-move new-board)))))

(defun read-a-legal-move (board)
  (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
               "~&That space is already occupied.")
           (read-a-legal-move board))
          (t pos))))

(defun board-full-p (board)
  (not (member 0 board)))

(defun computer-move (board)
  (let* ((best-move (choose-best-move board))
         (pos (first best-move))
         (strategy (second best-move))
         (new-board (make-move
                     *computer* pos board)))
    (format t "~&My move: ~S" pos)
    (format t "~&My strategy: ~A~%" strategy)
    (print-board new-board)
    (cond ((winner-p new-board)
           (format t "~&I win!"))
          ((board-full-p new-board)
           (format t "~&Tie game."))
          (t (opponent-move new-board)))))

(defun random-move-strategy (board)
  (list (pick-random-empty-position board)
        "random move"))


(defun pick-random-empty-position (board)
  (let ((pos (+ 1 (random 9))))
    (if (zerop (nth pos board))
        pos
      (pick-random-empty-position board))))

(defun make-three-in-a-row (board)
  (let ((pos (win-or-block board
                           (* 2 *computer*))))
    (and pos (list pos "make three in a row"))))


(defun block-opponent-win (board)
  (let ((pos (win-or-block board
                           (* 2 *opponent*))))
    (and pos (list pos "block opponent"))))


(defun win-or-block (board target-sum)
  (let ((triplet (find-if
                  #'(lambda (trip)
                      (equal (sum-triplet board
                                          trip)
                             target-sum))
                  *triplets*)))
    (when triplet
      (find-empty-position board triplet))))


(defun find-empty-position (board squares)
  (find-if #'(lambda (pos)
               (zerop (nth pos board)))
           squares))

(defun choose-best-move (board) ;Second version.
  (or (make-three-in-a-row board)
      (block-opponent-win board)
      (random-move-strategy board)))

person Aaron    schedule 06.10.2014    source источник
comment
Я нигде не вижу кода, связывающего *opponent*. Ты? Если нет, то вполне очевидно, почему он не связан.   -  person Charles Duffy    schedule 06.10.2014
comment
Черт возьми, извините, в какой-то момент я закомментировал следующее: (setf computer 10) (setf opponent 1)   -  person Aaron    schedule 06.10.2014
comment
В яблочко. Это ранее в книге, поэтому, по-видимому, когда вы внимательно следили за книгой, вы запустили рассматриваемый код, но затем пропустили его при просмотре IDE.   -  person Charles Duffy    schedule 06.10.2014
comment
Спасибо, чувак, иногда просто приятно получить публичное унижение '-_-   -  person Aaron    schedule 06.10.2014
comment
Пожалуйста, используйте defvar или defparameter для привязки глобальных специальных переменных. Setf просто устанавливает.   -  person Svante    schedule 06.10.2014


Ответы (1)


Если вы следуете инструкциям в книге, она говорит вам вызывать

(setf *computer* 10)
(setf *opponent* 1)

Видимо, вы не включили это в свой листинг кода.

В общем, если вы получаете сообщение об ошибке, что что-то не привязано, очевидно, что нужно найти код, который должен связать это со значением.

person Charles Duffy    schedule 06.10.2014