August 21, 2024

P91 - Knight's tour

Another famous problem is this one: How can a knight jump on an NxN chessboard in such a way that it visits every square exactly once?Hints: Represent the squares by pairs of their coordinates of the form (X Y), where both X and Y are integers between 1 and N.

Define a function (jump N (X Y)) that returns a list of the positions (U V) such that a knight can jump from (X Y) to (U V) on a NxN chessboard.

And finally, represent the solution of our problem as a list of N*N knight positions (the knight's tour).

lisp

;;; Knight's Tour
;;; uses function jump n x y, which gives a list of
;;; valid positions from x y in an nxn board

(setf jumps '
      ((+1 +2)
       (-1 +2)
       (-1 -2)
       (+1 -2)
       (+2 +1)
       (-2 +1)
       (-2 -1)
       (+2 -1))
      )       

(defun jump (n pair)
  "Returns the list of valid positions a knight's jump away from
   (X, Y) in an NxN board."
  (filter n
	  (mapcar #'(lambda (x) (mapcar #'+ pair x)) jumps)
	  )
  )

(defun filter (n lista)
  (if (null lista)
      ()
    (if (inside n (car lista))
	(cons (car lista) (filter n (cdr lista)))
      (filter n (cdr lista))
      )
    )
  )

(defun inside (n pair)
  (and (>= (car pair) 1)
       (<= (car pair) n)
       (>= (second pair) 1)
       (<= (second pair) n)
       )
  )

;;; now main function; it is based on dfs (see p87.lisp)

(defun knight (n)
  (one-longer n (* n n) () 0 (all-squares n))
  )

(defun one-longer (n nsqr ptour len nts)
  (cond
   ;; no more to see: failed
   ((null nts)
    nil)
   ;; next to see already a member: disregard it
   ((member (car nts) ptour :test #'equal)
    (one-longer n nsqr ptour len (cdr nts)))
   ;; next to see not a member: if there is a tour with this prefix, return it, otherwise try cdr
   (t (let ((tour (tour-with-prefix n nsqr (cons (car nts) ptour) (1+ len))))
	(if tour
	    tour
	  (one-longer n nsqr ptour len (cdr nts))
	  )))
   )
  )

(defun tour-with-prefix (n nsqr ptour len)
  (if (= len nsqr)
      ptour
    (one-longer n nsqr ptour len (jump n (car ptour)))
    )
  )

(defun all-squares (n)
  (if (= n 1)
      (last-line 1 1)
    (append (all-squares (1- n))
	    (last-line n n)
	    (last-col n (1- n))
	    )
    )
  )

(defun last-line (n k)
  (if (= k 1)
      (list (list 1 n))
    (cons (list k n) (last-line n (1- k)))
    )
  )

(defun last-col (n k)
  (if (= k 1)
      (list (list n 1))
    (cons (list n k) (last-col n (1- k)))
    )
  )
Be first to comment
Leave a reply