Dieter Komendera / Aug 05 2019
Clojure Maze Generation
As inspired by Maarten Metz:
0.8s
Clojure
(require [clojure.string :as s]) (declare print-maze) ;; Maze GENERATION (defn create-grid [rows cols] (vec (repeat rows (vec (repeat cols {}))))) (defn north-of [[row col]] [(dec row) col]) (defn south-of [[row col]] [(inc row) col]) (defn west-of [[row col]] [row (dec col)]) (defn east-of [[row col]] [row (inc col)]) (defn neighbours [grid cell] (filter (get-in grid %) ((juxt north-of east-of south-of west-of) cell))) (defn remove-border [grid c1 c2] (-> grid (update-in c1 conj c2) (update-in c2 conj c1))) (defn find-unvisited-neighbours [grid cell] (let [n (neighbours grid cell)] (filter (empty? (get-in grid %)) n))) (defn generate-maze [rows cols] (loop [maze (create-grid rows cols) backtrackstack ([0 0])] (if (empty? backtrackstack) (print-maze maze) (let [unvn (find-unvisited-neighbours maze (first backtrackstack))] (if (empty? unvn) (recur maze (rest backtrackstack)) (let [next (rand-nth unvn)] (recur (remove-border maze (first backtrackstack) next) (conj backtrackstack next)))))))) ;; Maze PRINTING (defn east-open-border? [maze cell] (contains? (get-in maze (east-of cell)) cell)) (defn south-open-border? [maze cell] (contains? (get-in maze (south-of cell)) cell)) (defn print-cell-body [maze cell] (if (east-open-border? maze cell) " " " |")) (defn print-cell-bottom [maze cell] (if (south-open-border? maze cell) " +" "---+")) (defn print-maze [maze] (let [result (atom []) rows (range (count maze)) cols (range (count (get-in maze [0])))] (swap! result conj "+" (repeat (count cols) "---+") "\n") (doseq [row rows] (swap! result conj "|") (doseq [col cols] (swap! result conj (print-cell-body maze [row col]))) (swap! result conj "\n" "+") (doseq [col cols] (swap! result conj (print-cell-bottom maze [row col]))) (swap! result conj "\n")) (println (s/join (flatten result)))))
user/print-maze
(def m (with-out-str (-> (generate-maze 10 15) print-maze))) (println m)
We can also write it to a file which will get stored in content addressed storage, so folks can download it:
We can also render it into an image directly. We just have to install some fonts first.
apt-get update apt-get install fonts-cantarell
(import java.awt.Color) (import java.awt.Font) (import java.awt.image.BufferedImage) (import javax.imageio.ImageIO) (let [bi (BufferedImage. 600 300 BufferedImage/TYPE_INT_ARGB) g (.createGraphics bi)] (.setColor g Color/BLACK) (loop [lines (clojure.string/split-lines m) y 10] (.setFont g (Font. "Courier" Font/PLAIN 10)) (when-let [l (first lines)] (.drawString g l 0 y) (recur (rest lines) (+ y 10)))) (ImageIO/write bi "png" (clojure.java.io/file "results/maze.png")))
true