Frank Buss wrote:

> could be enhanced easily for 3D and higher dimension mazes.

done:

(defun fill-maze (maze start add value dimensions &optional (index nil))
  (let ((max (car dimensions)))
    (if max
        (let ((rest (cdr dimensions)))
          (loop for i from start below max by add do
                (fill-maze maze start add value rest (cons i index))))
      (setf (apply #'aref maze (reverse index)) value))))

(defun get-possible-directions (maze ofs position maze-dimensions)
  (let ((dimension-count (length maze-dimensions)))
    (loop for i from 0 below dimension-count 
          with directions = '()
          finally (return directions) do
          (loop for ofs from (* -1 ofs) to (* 1 ofs) by (* 2 ofs)
                with add do
                (setf add t)
                (let ((direction
                       (loop for j from 0 below dimension-count
                             for p in position
                             for d in maze-dimensions collect
                             (let ((coord 
                                    (if (= i j)
                                        (+ ofs p)
                                      p)))
                               (when (or (< coord 0)
                                         (= coord d))
                                 (setf add nil)
                                 (loop-finish))
                               coord))))
                  (when (and add (not (apply #'aref maze direction)))
                    (push direction directions)))))))

(defun create-maze (dimensions)
  "Create a so called 'perfect maze'"
  (let* ((maze-dimensions (loop for i in dimensions collect (1+ (* 2 i))))
         (maze (make-array maze-dimensions
                           :initial-element nil))
         (position (loop for i in dimensions collect (1+ (* 2 (random
i)))))
         (stack '())
         (size (* (reduce #'* dimensions)))
         (visited 0))
    ;; fill with walls
    (fill-maze maze 0 1 :wall maze-dimensions)
    ;; delete markers
    (fill-maze maze 1 2 nil maze-dimensions)
    ;; break walls
    (loop while (< visited size) do
          (unless (apply #'aref maze position)
            (setf (apply #'aref maze position) :visited)
            (incf visited))
          (let ((directions (get-possible-directions maze 2 position
maze-dimensions)))
            (if (car directions)
                (let* ((new-position (elt directions
                                          (random (length directions)))))
                  (push new-position stack)
                  (setf (apply #'aref maze (loop for i in new-position
                                                 for j in position
                                                 collect (ash (+ i j) -1)))
                        nil)
                  (setf position new-position))
              (setf position (pop stack)))))
    ;; delete markers
    (fill-maze maze 1 2 nil maze-dimensions)
    maze))

(defun print-maze-layer (maze dimensions &optional (index nil))
  (let ((max (car dimensions)))
    (if (> (length dimensions) 2)
        (let ((rest (cdr dimensions)))
          (loop for i from 0 below max do
                (print-maze-layer maze rest (cons i index))))
    (loop for y from 0 below (cadr dimensions) do
          (loop for x from 0 below (car dimensions) do
                (princ (case (apply #'aref maze (append index (list x)
(list y)))
                         (:path ".")
                         (:wall "#")
                         (t " "))))
          (terpri)))
    (terpri)))

(defun print-maze (maze)
  "Print a maze"
  (print-maze-layer maze (array-dimensions maze)))

(defun solve-maze (maze)
  "Return t, if maze is solved (filled with :path) or nil if not solvable"
  (let* ((maze-dimensions (array-dimensions maze))
         (position (loop for i in maze-dimensions collect 1))
         (end (loop for i in maze-dimensions collect (- i 2)))
         (stack '())
         (size (* (reduce #'* maze-dimensions)))
         (visited 0))
    (loop while (< visited size) do
          (unless (apply #'aref maze position)
            (setf (apply #'aref maze position) :path)
            (incf visited))
          (when (equalp position end) (return-from solve-maze t))
          (let ((directions (get-possible-directions maze 1 position
maze-dimensions)))
            (if (car directions)
                (let* ((new-position (elt directions
                                          (random (length directions)))))
                  (push position stack)
                  (setf position new-position))
              (let ((new-position (pop stack)))
                (unless new-position (return-from solve-maze))
                (setf (apply #'aref maze position) :dead-end)
                (setf position new-position)))))))

(defun test-2d ()
  (let ((maze (create-maze '(16 10))))
    (solve-maze maze)
    (print-maze maze)))

(defun test-3d ()
  (let ((maze (create-maze '(2 16 10))))
    (solve-maze maze)
    (print-maze maze)))

(defun test-4d ()
  (let ((maze (create-maze '(3 3 5 4))))
    (solve-maze maze)
    (print-maze maze)))


-- 
Frank Buss, [EMAIL PROTECTED]
http://www.frank-buss.de, http://www.it4-systems.de

_______________________________________________
Gardeners mailing list
[email protected]
http://www.lispniks.com/mailman/listinfo/gardeners

Reply via email to