Код легко восстановить. Но ваше решение - не лучший стиль, поскольку колышки являются глобальными переменными.
Основная путаница в вашем коде - между списками и переменными. Макросы, такие как PUSH и POP, работают над «местами», такими как значения символов, переменные или слоты объектов. Непосредственное использование списка не работает должным образом.
(defvar *peg1* '())
(defvar *peg2* '())
(defvar *peg3* '())
Обязательно сравнивайте символы, а не значения.
(defun peg-name (peg)
(cond ((equal peg '*peg1*) "Peg 1")
((equal peg '*peg2*) "Peg 2")
((equal peg '*peg3*) "Peg 3")))
Поскольку мы передаем символы, нам нужно выскочить и нажать на значения символа.
(defun move-disk (from to)
(let ((disc (pop (symbol-value from))))
(format t "Move ~a from ~a to ~a~%" disc (peg-name from) (peg-name to))
(push disc (symbol-value to))))
(defun transfer (n source aux dest)
(when (> n 0)
(transfer (1- n) source dest aux)
(move-disk source dest)
(transfer (1- n) aux source dest)))
Передайте символы, а не списки. Также полезно сбросить другие колышки.
(defun hanoi (disk-list)
(setq *peg1* disk-list)
(setq *peg2* '())
(setq *peg3* '())
(transfer (length disk-list) '*peg1* '*peg2* '*peg3*))
Тест:
CL-USER 15 > (hanoi '(Small Medium Large))
Move SMALL from Peg 1 to Peg 3
Move MEDIUM from Peg 1 to Peg 2
Move SMALL from Peg 3 to Peg 2
Move LARGE from Peg 1 to Peg 3
Move SMALL from Peg 2 to Peg 1
Move MEDIUM from Peg 2 to Peg 3
Move SMALL from Peg 1 to Peg 3
NIL
CL-USER 16 > *peg3*
(SMALL MEDIUM LARGE)
CL-USER 17 > *peg1*
NIL