First, establish some of the cell data ```lisp ; This will result in a "2x2" cell, of [0 1 1 1], with 0 representing an empty ; space, and 1 representing a wall. (var (hall-width wall-width) (values 1 1)) ; This sets the "map width". This means 10 cells across and down. With each cell ; being 2x2, this results in a 20x20 square map. All maps will be square (for ; now). (var num-cells 10) ; Explicitly setting cell-size for convenience. All cells are squares (var cell-size (+ hall-width wall-width)) ``` Next, generate the initial array of cells to work with. ```lisp (var cells {}) (for [i 1 (* num-cells num-cells)] (table.insert cells { :n false :s false :e false :w false :v false :o false })) ``` `:n`, `:s`, `:e`, `:w` - if cell has a directional connection `:v` - has the cell been visited `:o` - does the cell contain an obstacle With the cells established, can use a recursive depth-first search with a stack to generate the maze. For ease, we'll always start along the top. Eventually, want to ensure the solution is along the sides or bottom. ```lisp (var cell-stack [(math.random 1 num-cells)]) (while (> 0 (length cell-stack) (var current-cell (table.remove cell-stack (length cell-stack))) (tset cells current-cell :v true) ; Check if any of the current cell's neighbors are ; 1. unvisited ; 2. a side/barrier wall (var next-cells {}) ; North - ; if current-cell <= num-cells, then north is a map-side/barrier (when (> num-cells current-cell) (var n-cell (- current-cell num-cells)) (if (not (. cells n-cell :v)) (table.insert next-cells n-cell))) ; South - ; if current-cell > (- (* num-cells num-cells) num-cells), ; then south is a map-side/barrier (when (< current-cell (- (* num-cells num-cells) num-cells)) (var s-cell (- (* num-cells num-cells) num-cells)) (if (not (. cells s-cell :v)) (table.insert next-cells s-cell))) ; East - ; if current-cell % num-cells = 0, then east is a map-side/barrier (when (not (= 0 (% current-cell num-cells))) (var e-cell (+ current-cell 1)) (if (not (. cells e-cell :v)) (table.insert next-cells e-cell))) ; West - ; if current-cell % num-cells = 1, then west is a map-side/barrier (when (not (= 1 (% current-cell num-cells))) (var w-cell (- current-cell 1)) (if (not (. cells e-cell :v)) (table.insert next-cells w-cell))) ``` --- For output: Each cell is then used to generate values in the map array. Each cell will have either a hallway or a wall at each position, for `cell-size` positions. Iterate through each cell. Cells 1 through `num-cells` are the first row, then (1 + `num-cells`) through (`num-cells` * 2), and so on. This can be generalized and extrapolated to `(x + (num-cells * (y - 1)))` through `(num-cells * y)`, for `x` and `y` loops from 1 to `num-cells`. ```lisp (for [i 1 num-cells] (for [j 1 num-cells] ``` Each cell is of uniform size, and the map is a square that divides evenly by that size. We established the width, and that value squared is the map. Every cell is numbered from 1 to `(* num-cells num-cells)` (ie., 1 to 100). The index of the cell divided by `num-cells`, plus 1, gets the row: ```lisp (fn row [i] (+ 1 (// i num-cells))) ``` This gets the "upper-left" for the map array, given a cell index. ```lisp (fn c [i] (+ (- (* i cell-size) 1) (* cell-size cell-num (- (row i) 1)))) ``` Using that index, iterate through the cell based on `cell-size` twice, using each loop to add either `(- i 1)` and `(* (- j 1) cell-num)` to the value from `c` above, and insert it into the map array. --- For cell generation: Each cell is a combination of hallways and walls. For each cell, if the "row" or "column" is less than the `hall-width`, enter a "0", otherwise enter a "1". ```lisp (var cell []) (for [i 1 cell-size] (for [j 1 cell-size] (var cell-index (+ j (* (- i 1) cell-size))) (if (and (< i (+ hall-width 1)) (< j (+ hall-width 1))) (tset cell cell-index 0) (tset cell cell-index 1)))) ```