Skip to content

Generating a Shaped Maze ​

A mask excludes cells from a square, triangular, or hexagonal grid. Use one when the maze should follow a logo, room outline, image silhouette, or another custom shape.

Describing the Shape ​

A mask is indexed as mask[row][column]. true keeps a cell and false removes it:

ts
const mask = [
  [true, true, true, true, true],
  [true, false, false, false, true],
  [true, true, true, true, true],
] as const

Pass the mask with matching square-grid dimensions:

ts
import { createMaze } from 'mazely'

const maze = createMaze({
  grid: {
    type: 'square',
    rows: mask.length,
    cols: mask[0].length,
    mask,
  },
  seed: 'masked-example',
})

maze.generate('wilson').finish()

Excluded cells and their attached edges do not exist in maze.grid.

Triangle grids accept masks too. For a triangular outer layout, row r has 2r + 1 cells, so each mask row should follow that shape:

ts
const triangleMask = [
  [true],
  [true, true, true],
  [true, true, false, true, true],
] as const

const triangleMaze = createMaze({
  grid: {
    type: 'triangle',
    layout: 'triangle',
    size: triangleMask.length,
    mask: triangleMask,
  },
})

triangleMaze.generate('dfs').finish()

A rectangular triangle layout uses an ordinary rows × cols mask. The cells are still triangles; layout changes only the outer boundary.

Hexagonal grids accept masks indexed by their logical row and col too. A rectangular Hex layout uses an ordinary rows × cols mask; an outer Hex layout uses its (2 × size - 1) × (2 × size - 1) bounding box, where cells outside the six-sided boundary are ignored:

ts
const hexMaze = createMaze({
  grid: {
    type: 'hexagon',
    layout: 'rectangle',
    orientation: 'pointy',
    rows: 6,
    cols: 8,
    mask: hexMask,
  },
})

Keeping Active Cells Connected ​

Every active cell must be reachable from every other active cell through a shared grid edge. This square mask is disconnected:

ts
const disconnectedMask = [
  [true, false],
  [false, true],
]

Diagonal contact does not connect square cells. Triangle cells have at most three neighbors: left, right, and one vertical neighbor determined by their orientation. Hex cells have up to six neighbors. Generation validates connectivity using the selected grid's actual edges and rejects a disconnected mask before changing edge state.

Applications that create square-grid masks from images can run a four-directional flood fill first to provide more specific feedback. A triangle- or hex-grid image converter must instead use its cell coverage and topology adjacency. Mazely still performs its own connectivity validation.

Choosing Valid Start and End Points ​

Generation and solving coordinates must refer to active cells:

ts
maze.generate('dfs', {
  start: { x: 0, y: 0 },
}).finish()

maze.solve('bfs', {
  start: { x: 0, y: 0 },
  end: { x: 4, y: 2 },
}).finish()

A point outside the grid or on an excluded cell throws a RangeError.

Understanding the Topology ​

A mask removes cells but does not change their topology. Use type: 'square' for four-sided cells, type: 'triangle' for alternating three-sided cells, or type: 'hexagon' for six-sided cells; the mask is interpreted using that grid's neighbor and edge rules.

To persist a masked maze, store the mask next to the serialized topology. See Saving and Restoring a Maze.

Released under the MIT License.