Every click of the New Maze button produces a board that has never existed before — yet every board is guaranteed to be solvable, have the correct number of open cells, and require at least 12 moves to traverse from start to treasure. This is the job ofDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/treasure-hunt-game/llms.txt
Use this file to discover all available pages before exploring further.
createRandomMaze(), a two-phase carve-and-validate algorithm that first cuts a single winding path from [0,0] to [7,7], then fills in additional dead-end branches to hit a target cell density, and finally validates that the resulting maze meets the minimum path-length requirement before returning the board.
Function Signature and Return Shape
| Parameter | Default | Description |
|---|---|---|
rows | 8 | Number of rows in the grid |
cols | 8 | Number of columns in the grid |
density | 0.55 | Target fraction of cells that should be open (0–1) |
maze— the completed 8×8 two-dimensional array (1= open,0= blocked)solution— an array of[row, col]pairs representing the shortest path from[0,0]to[7,7]as computed by BFS after generation
Phase 1: carveUniqueMainPath
The first phase builds the backbone of the maze — a single connected corridor from start to target. It uses a depth-first walk with backtracking:
Initialize
Create a fully blocked (
0) grid of the requested size. Open the start cell [0,0] and add it to the active path stack and the seen set.Shuffle and filter candidates
From the current head of the path, apply all four
ACTION_DELTAS to get neighboring cells. Shuffle the results randomly, then filter to keep only cells that are:- Inside the grid boundaries
- Not already in the
seenset - Have at most 1 open neighbor (
openNeighborCount ≤ 1) — this prevents the carver from accidentally creating shortcuts or merging two corridors into a loop
Heuristic sort toward the target
Sort the filtered candidates by Manhattan distance to
[7,7]. 68% of the time the sort prefers closer cells (greedy progress); 32% of the time it flips the sort, allowing the path to meander and produce varied layouts.Advance or backtrack
If at least one candidate exists, open the first one, add it to the path and
seen, and continue. If no candidates exist and the path has more than one cell, remove the current head (path.pop()), close it again (maze[row][col] = 0), and retry from the previous cell. Up to 5,000 attempts are made before giving up.The openNeighborCount Guard
≤ 1. This single guard is what prevents the depth-first walk from creating parallel corridors that join back together — which would undermine the maze’s structure and allow unintended shortcuts around walls.
Phase 2: addDeadEnds
After the main path is carved, most of the grid is still 0. addDeadEnds opens additional cells to reach the density target, but it only opens cells that would form a dead-end branch rather than a shortcut:
Validation and Retry Logic
After both phases complete,createRandomMaze runs a BFS validation pass on the result:
- The start cell
[0,0]and target cell[7,7]are explicitly forced open afteraddDeadEnds, regardless of what the carver did. findShortestPath(BFS) computes the shortest route on the finished board.- The maze is only accepted if the shortest path contains at least 12 cells (i.e., at least 11 moves). This prevents trivially short boards where the treasure is just a few steps away.
- Up to 70 attempts are made before falling back to the
ORIGINAL_MAZEconstant.
The density Parameter
The density value determines what fraction of the 64 cells should be open when generation finishes:
| Density | Open cells (8×8) | Used when |
|---|---|---|
0.56 | ~36 cells | Easy and Medium difficulty (via newMaze() in app.js) |
0.55 | ~35 cells | createRandomMaze() function default (no argument passed) |
0.50 | ~32 cells | Hard difficulty (via newMaze() in app.js) |
0.5 density because fewer open cells mean fewer route options, which rewards players who learn the maze and punishes inefficient exploration. The app.js call that supplies this value:
Fallback: ORIGINAL_MAZE
If all 70 attempts fail to produce a maze with a path of length ≥ 12, the generator returns a cloned copy of the static ORIGINAL_MAZE alongside its pre-computed BFS solution:
carveUniqueMainPath produces a valid connected path on the vast majority of attempts.
Every maze returned by
createRandomMaze — whether freshly generated or the ORIGINAL_MAZE fallback — satisfies three hard guarantees: the start cell [0,0] is open, the target cell [7,7] is open, and there is at least one valid path between them that is 12 or more moves long. No maze will ever be handed to the game engine in an unsolvable state.