(defun scramble (list) (let ((out ())) (each ((item list)) (let ((r (rand (+ 1 (length out))))) (set [out r..r] (list item)))) out)) (defun rnd-pick (list) (if list [list (rand (length list))])) (defun neigh (loc) (let ((x (from loc)) (y (to loc))) (list (- x 1)..y (+ x 1)..y x..(- y 1) x..(+ y 1)))) (defun make-maze-impl (vi pa sc cu) (let ((fr (hash :equal-based)) (q (list cu)) (c sc)) (set [fr cu] t) (while q (let* ((cu (first q)) (ne (rnd-pick (remove-if (orf vi fr) (neigh cu))))) (cond (ne (set [fr ne] t) (push ne [pa cu]) (push cu [pa ne]) (push ne q) (cond ((<= (dec c) 0) (set q (scramble q)) (set c sc)))) (t (set [vi cu] t) (del [fr cu]) (pop q))))))) (defun make-maze (w h sf) (let ((vi (hash :equal-based)) ;; visited hash (pa (hash :equal-based)) ;; path connectivity hash (sc (max 1 (int-flo (trunc (* sf w h) 100.0))))) ;; go straight count (each ((x (range -1 w))) (set [vi x..-1] t) (set [vi x..h] t)) (each ((y (range* 0 h))) (set [vi -1..y] t) (set [vi w..y] t)) (make-maze-impl vi pa sc 0..0) ;; Open start and end (push 0..-1 [pa 0..0]) (push (- w 1)..(- h 1) [pa (- w 1)..h]) pa)) (defun print-tops (pa w j) (each ((i (range* 0 w))) (if (memqual i..(- j 1) [pa i..j]) (put-string "+ ") (put-string "+----"))) (put-line "+")) (defun print-sides (pa w j) (let ((str "")) (each ((i (range* 0 w))) (if (memqual (- i 1)..j [pa i..j]) (set str `@str `) (set str `@str| `))) (put-line `@str|\n@str|`))) (defun print-maze (pa w h) (each ((j (range* 0 h))) (print-tops pa w j) (print-sides pa w j)) (print-tops pa w h)) (defun usage () (let ((invocation (ldiff *full-args* *args*))) (put-line "usage: ") (put-line `@invocation []`) (put-line "straightness is a percentage, defaulting to 15") (exit 1))) (let ((args [mapcar num-str *args*])) (if (memq nil args) (usage)) (tree-case args ((w h s ju . nk) (usage)) ((w h : (s 15)) (set w (max 1 w)) (set h (max 1 h)) (print-maze (make-maze w h s) w h)) (else (usage))))