Skip to content

Instantly share code, notes, and snippets.

@jtzeng
Created November 8, 2013 09:04
;; Knight's tour using Warnsdorff's rule.
;; https://en.wikipedia.org/wiki/Knight%27s_tour
(defconstant +board-sz+ 8)
(defparameter *board* (make-array `(,+board-sz+ ,+board-sz+) :initial-element 0))
(defconstant +knight-moves+
'(#(1 -2) #(2 -1) #(2 1) #(1 2) #(-1 2) #(-2 1) #(-2 -1) #(-1 -2)))
(defun board-at (x y)
(aref *board* y x))
(defun board-set (x y val)
(setf (aref *board* y x) val))
(defun print-board ()
(dotimes (y +board-sz+)
(dotimes (x +board-sz+)
(format t "[~d] " (board-at x y))) (terpri)))
(defun is-valid-sq (x y)
(and (>= x 0) (>= y 0) (< x +board-sz+) (< y +board-sz+) (zerop (board-at x y))))
(defun get-moves (x y)
(remove-if-not (lambda (lst)
(apply #'is-valid-sq lst))
(mapcar (lambda (mvmt)
(let ((new-x (+ x (aref mvmt 0)))
(new-y (+ y (aref mvmt 1))))
(list new-x new-y))) +knight-moves+)))
(defun get-min-move (moves)
(if (null moves)
nil
(apply #'min (mapcar (lambda (move)
(length (get-moves (car move) (second move)))) moves))))
(defun next-sq (x y)
(let* ((moves (get-moves x y))
(min-move (get-min-move moves)))
(when (null moves)
(return-from next-sq nil))
(dolist (move moves)
(when (= min-move (length (get-moves (car move) (second move))))
(return-from next-sq move)))))
(defun sq-name (x y)
(format nil "~C~D" (code-char (+ (char-int #\a) x)) (abs (- y +board-sz+))))
(defun begin-tour (x y)
(format t "Moved to ~A~%" (sq-name x y))
(let ((next (next-sq x y)))
(board-set x y 1)
(print-board)
(when (null next)
(format t "No more moves!~%") (quit))
(apply #'begin-tour next)))
(begin-tour 0 0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment