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))
    (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 [])
(each [k v (ipairs meta-cells)]
    (var row-limit (if (. v :e) (+ hall-width wall-width) hall-width))
    (var col-limit (if (. v :s) (+ hall-width wall-width) hall-width))
    (for [i 1 cell-size]
        (for [j 1 cell-size]
            (var cell-index (+ j (* (- i 1) cell-size)))
            (if (and (< i (+ col-limit 1)) (< j (+ row-limit 1)))
                    (tset cell cell-index 0)
                    (tset cell cell-index 1))
            (if (and (> i hall-width) (> j hall-width))
                    (tset cell cell-index 1))))
```

This becomes a bit more challenging with considering connections. It is likely a
matter of modifying the conditional such that: when there is a horizontal
connection, check for `i` to be less than the entire cell width (`hall-width` +
`wall-width`); and then similar for `j` with vertical connections. However, this
will then remove the corner wall when there are both vertical and horizontal
connections. This could be solved by checking if both `i` and `j` are beyond
`hall-width`, which would represent the always corner.

The above code should translate from a `meta-cells` list of meta-data to a
`cells` list of 0's and 1's. 

---
With a bit of modification, the logic for the maze generation from above appears
to work. There is one challenge which remains, which is updating the walls. A
way around this is to make the data about the next cell more verbose: include
not only the cell number, but also the direction. Then, use a case statement to
update accordingly.

The last remaining tasks are to buffer the entire maze, such that there are two
cells worth of walls around it; and to establish starting and ending squares.

Creating the buffer means adding two cells worth of walls to the north and west
walls, and 1 cell worth of walls to the south and east walls.  This should
theoretically be very easy using `table.insert`, which automatically modifies
all further table values. However, will need to be mindful when updating east
and west. Updating north is just `(table.insert 1 1)` for `(* cell-num cell-size
cell-size)` times twice. Similar for south, except `(table.insert 1)` for `(*
cell-num cell-size cell-size)` once. East and west seem more challenging.
Though, thinking about it for a moment, I could essentially migrate the
generated array one "row" at a time into a new array, padding it on either side
as I do so. I believe this may be the way. I can use `table.move` to accomplish
this.

As part of the padding, I also need to translate the map from a single list into
a list of lists. Again, this can be done using the `table.move` function and
`table.insert`.

```lisp
(var map [])
(var map-row [])
(table.move cell_map x y 1 map-row)
(table.insert map map-row)
```

---
Remaining tasks:
1. Finalize map generation:
    [X] Establish starting spot, and add the northern feature spawn point.
    [X] Establish ending spot, and add the southern feature finale point.
    [O] Modify the map wall values to account for random wall heights.
        - This "works", but the walls are all only the front of the square, so
        it looks odd.
2. Draw floors
3. Draw sky-boxen
4. Add monster mechanics

---
Thinking about a HUD. On the top can be a compass, and then on the bottom can be
a few additional things.

For the compass, I know the direction of the player. I've implemented the state
function again, and am writing that data to it and reading from it for the
overlay. When the `player.getX` is greater than 0, I'm "facing" north; when less
than 0, facing south. For the `player.getY`, greater than 0 is west; less than
is east. It's easy to just print the value, but it'd be really cool to instead
print one of those compass bars. Theoretically it's printing out the elements of
a list at set screen intervals. The list may look like:

```lisp
(var compass-bar [":" "|" "N" "|" ":" "|" "E" "|" ":" "|" "S" "|" ":" "|" "W" "|"])
```

Then it would print 5 elements, starting at x, going to x + 5, wrapping around.
`x` would be determined based on the two values of `player.getX` and
`player.getY`.

This will ensure we loop properly through the indexes, assuming `x` is always
larger than the array length.
```lisp
(fn fi [x] (set r x) (while (> r 5) (set r (- r 5))) r)
```

Beyond this, it may be good to pair this with logic that allows adding or
subtracting from the index and not escaping the list. This would basically check
if the new index will be either less-than 0 or greater than the list length, and
adjust accordingly.

Could be something like:

```
(if x > 0) // northern half
    index is set to north
    (adjust index by ratio of y to (-1 .. 1))
(else) // southern half
    index is set to south
    (adjust index by ratio y to (-1 .. 1))
```

The adjustment algorithm is the same, and it's either added or subtracted from
the index, based on which hemisphere, probably?

This value `(math.floor (+ 10 (* 10 (player.getDirX))))` yields 0-19 in both an
east and west facing arc. If I use east and west as a switch, then when I'm
facing east I can move the compass bar list in one direction, and the other when
facing west.

In order to do this I need a proper circular-list approach.

```lisp
(var compass [<elements>])
(fn circular-compass [c n]
    (if (< (+ c n) 1) (length compass)
        (> (length compass) (+ c n)) 0
        (+ c n))
```

---
Compass bar "works", at least well enough for now. Time to move to some menus. I
think a cool aesthetic would be the start menu being like the inside of the
escape pod you start outside of. The background would be a texture of some kind
of metallic wall, and there could be a flashing light effect. The menu items
would be the configuration for the maze: size, number of survivors, etc.. There
would be a button to start, and then a button to quit. If I have time, there can
be a button to remap keys, and maybe turn sound on and off.

Focusing on the menu buttons themselves, each one has a shape and text.
Additionally, each one should have a hover effect. Each menu can have a
left-action, right-action, and select-action.

```lisp
(var menu-font (love.graphics.newFont 20))
(fn menu-button [x y text la ra sa]
    (love.graphics.polygon ...)
    (love.graphics.printf text menu-font x (+ y ...) (+ x ...))
    (var (left-area right-area mid-area) (values  ...))
    (when (left-area) (la))
    (when (right-area) (ra))
    (when (mid-area) (sa))
```

There should also be a way to navigate with the keyboard. Using up and down
arrows or keys will move the "selected" button, left/right arrows/keys will
activate the left/right actions, and enter/use will activate the select action.

Start simple, make the polygon a square, make the areas square. Add buttons for
survivors and supplies and monster and stuff, even though it's not implemented
yet.
