lispjam-autumn-2024/notes.md

4.1 KiB

First, establish some of the cell data

; 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.

(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.

(var cell-stack [(math.random 1 num-cells)])

(while (> 0 (length cell-stack)
    (var current-cell (table.remove 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.

(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:

(fn row [i] (+ 1 (// i num-cells)))

This gets the "upper-left" for the map array, given a cell index.

(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".

(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))))