View: Multi-Page Single Page

API Reference

The public surface: generating, the maze data, playing, solving, pictures, assets and the demo.

Assemblies

Assembly and namespaceWhat's in it
SimpleMazeThe core: generation, the maze data, the play rules, the solver, pictures and the ScriptableObjects. It references no packages, and everything except the two asset types is plain C# that also runs outside Unity.
SimpleMaze.DemoThe 3D demo: the view, the game, the HUD, the hub, sounds and effects. It uses the Input System and Unity UI packages, and HDRP when that package is installed.
SimpleMaze.EditorThe Maze Generator window, the inspectors and the documentation menu. Editor only.

Everything below is in the SimpleMaze namespace unless it says SimpleMaze.Demo.

MazeGenerator

The entry point. Every method copies and clamps the settings first, so your object is never changed, and the same settings with the same seed always give the same maze. A null settings object means the defaults, and an empty seed means a fresh random one.

MethodWhat it does
MazeData Generate(MazeSettings settings)One maze from this exact seed, solved and rated.
MazeData GenerateVerified(MazeSettings settings, CancellationToken cancel = default) Tries the seed, then the seed with #1, #2 and so on, up to MaxAttempts, until a maze is sound: solvable, a fair race, no soft-lock and enough coverage when asked for, and the target stars. On a miss it returns the closest maze with a note. If it is cancelled before the first maze, it throws OperationCanceledException.
List<MazeData> GenerateBatch(MazeSettings settings, int count, CancellationToken cancel = default) A pack of verified mazes with seeds root-0, root-1 and so on.
Task<MazeData> GenerateAsync(...), GenerateVerifiedAsync(...)The same on a background thread.
Task<List<MazeData>> GenerateBatchAsync(MazeSettings settings, int count, IProgress<int> progress = null, CancellationToken cancel = default) A batch on a background thread, reporting how many are done (1 to count).

MazeSettings and enums

MazeSettings holds every input to the generator. Each field, its range and what it does is on the Generating page. It also has:

MemberWhat it does
MazeSettings Clamp()Puts every field into its valid range, in place, and returns the same object.
MazeSettings Clone()A copy.
bool HasGimmicksTrue when any gimmick is asked for.
EnumValues
GridShapeSquare, Hex, Triangle, Circular
CarveAlgorithmRecursiveBacktracker, Prim, Kruskal, Wilson, HuntAndKill, GrowingTree
EndpointsFarthest, CenterOut, OutsideIn, Fixed
MovementStep, Roll
ShapeKindNone, Circle, Ring, Heart, Star, Diamond, Cross, Text, Custom
ShapeSourceDark, Light, Opaque (which pixels of a picture are inside)

TopologySpec describes the board: Shape, Width, Height, Rings, FirstRing and Floors. Build one with TopologySpec.Grid(shape, width, height) or TopologySpec.Circle(rings, firstRing = 0), and Clamp() returns a copy with every field in range.

MazeData

A finished maze: the board, the passages, the players and gimmicks, and the solver's verdict stamped on it. It is serializable, so it stores inside a ScriptableObject, and plain C#, so it works outside Unity too. Cells are numbered as described in Cells and slots.

Board
TopologySpec GridThe board this maze is carved on.
string SeedThe seed that made it. With Settings it rebuilds this exact maze.
CarveAlgorithm AlgorithmHow it was carved.
int[] MasksEach cell's open sides: bit s set means slot s is open.
List<int> HolesCells removed from the board, including the ones a shape cut away.
ShapeKind Shape, List<int> OutsideThe shape it was cut to and the cells the shape cut away.
List<MazeRoom> RoomsThe open rooms, each a list of Cells.
List<Tunnel> TunnelsWeave crossings: each runs under the corridor cell Over, joining A and C on either side of it.
Players
List<int> Starts, List<int> GoalsOne start per player. One goal per player, or a single goal everyone heads to.
int Start, int GoalPlayer 1's start and goal.
int PlayerCountHow many players.
int GoalOf(int player)The goal that player heads to.
bool SharedGoalEvery player heads to Goals[0].
Movement MovementHow the players move. When Roll can't be used (a board that can't roll, or no start that rolls into the goal), the maze is stored as Step, with a note.
Gimmicks
List<int> KeysKeys[k] is the cell holding key k. Taking it opens every door of colour k for good.
List<Door> DoorsLocked sides: Cell, Slot and the Key colour that opens it. A door blocks both ways.
List<Switch> Switches, List<Gate> GatesA switch has a Cell and a Channel (0 to 3). A gate has a Cell, a Slot, the Channel that flips it, and StartsOpen for a decoy the switch shuts.
List<int> GemsEvery gem must be collected before a goal lets a player in.
List<int> TrapsTrap cells. Stepping or rolling onto one fails.
List<OneWay> OneWaysA side you can leave Cell through Slot, but never come back.
List<Portal> PortalsPairs of cells A and B. Entering either puts you on the other.
The verdict
bool SolvableThe solver proved every player can reach its goal.
int ParThe proven minimum: steps, or rolls. With several stepping players it is the total of their routes. -1 means unsolvable or not verified.
List<int> PlayerParsStep: each player's own par.
bool FairFalse only for a race (Step, several players, one goal) whose players' pars differ.
long OptimalCount, bool CountCompleteHow many different best solutions there are. When CountComplete is false the count was cut short and is a lower bound.
bool UniqueExactly one best solution, proven.
bool CanGetStuckSome reachable position can no longer reach the goal (a soft-lock).
int Difficulty, int ScoreThe 1 to 5 star rating (0 when unsolvable) and the raw score it comes from.
List<int> SolutionPlayer 1's positions along a best solution, start first. Step lists every cell, Roll lists where the player comes to rest after each roll.
List<PlayerRoute> RoutesStep with several players: each player's best route as Cells.
List<int> MovesRoll: the directions of the best solution.
Facts and notes
int DeadEnds, int Junctions, int LoopsCells with one way in or out, cells where three or more ways meet, and independent loops (0 is a perfect maze).
int SolutionLength, int Decisions, int RealDecisionsSteps on player 1's shortest route through the bare maze, the forks on it, and the forks whose wrong way runs 3 or more cells deep.
float CoverageThe fraction of the maze the best solution passes through (0 to 1).
int ShortcutsDoors and first gates a player can walk around.
MazeSettings SettingsThe settings it was made with.
List<string> NotesWhat the generator adjusted or couldn't do.
Helpers
Topology Topology, int CellCountThe grid, built from Grid on first use.
bool IsOpen(int cell, int slot)Is this side open? (Doors and one-way sides are open sides with a rule on them.)
bool IsHole(int cell)Is this cell removed from the board?
Passages ToPassages()An editable copy of the passages.

Cells and slots

A cell is an index from 0 to CellCount - 1, and each side of a cell is a slot. Use Topology.Neighbor(cell, slot) to find the cell across a side and SlotTo(cell, other) for the side between two neighbours.

GridCell indexSlots
Squarey * Width + x, row 0 at the bottom0 N, 1 E, 2 S, 3 W
Hexy * Width + x, row 0 at the bottom, odd rows shifted half a cell right 0 E, 1 NE, 2 NW, 3 W, 4 SW, 5 SE
Triangley * Width + x, row 0 at the bottom; cell (x, y) points up when x + y is even0 left, 1 right, 2 the flat side
Circular0 is the centre, then each ring counter-clockwise from angle 00 counter-clockwise, 1 clockwise, 2 inward, then one outward slot per cell in the next ring (the centre has one slot per first-ring cell)
Floorsfloor * cells per floor + base cellThe base grid's slots, then Up and Down (the ground floor has no Down slot and the top floor no Up slot)

Roll directions use the same numbers as the slots on Square and Hex.

Playing: MazeRules

Your game keeps a MazePlay and asks MazeRules what each move does. These are the same rules the solver counted with, so the game and the par always agree.

MazePlay
int[] PositionsEach player's cell (-1 once home).
bool[] HomeWhich players are home.
int[] KeysKeys held, one bit per colour, per player (on Roll every entry is the same, because keys are shared). Bits 16 to 19 are the switch channels flipped an odd number of times; read a gate with MazeRules.IsGateOpen.
int[] GemsGems collected, one bit per gem, per player.
MazePlay Clone()A copy, for undo.
MazeRulesWhat it does
MazePlay NewGame(MazeData m)Every player on its start, nothing held.
bool TryStep(MazeData m, MazePlay play, int player, int toCell, out string reason) Moves one player one cell: a neighbour, the far end of a tunnel, or up or down the stairs. On success the position is updated in place, including portals, pickups, switches and getting home. Otherwise it returns false with the reason, such as a wall, a locked door, a shut gate, a one-way side or a trap. There is also an overload without reason.
RollResult Roll(MazeData m, MazePlay play, int dir, List<int>[] trails = null) Rolls every player in direction dir. play is not changed. The result has After (the new position), Moved (false for a wasted roll) and Trapped (someone rolled onto a trap, so the roll fails). The optional trails, one list per player, receive every cell each player passes, for animation.
bool Hint(MazeData m, MazePlay play, int player, out int move, int stateBudget = 500_000) The first move of a best way on from here. On Step move is the cell to step to, and on Roll the direction. False with -1 when it's solved, that player is home, there is no way on (a soft-lock) or the search ran out of budget.
bool IsSolved(MazeData m, MazePlay play)Every player is home.
bool IsGateOpen(MazePlay play, int player, Gate gate)Is this gate open for that player now?
bool CanRoll(GridShape shape), bool CanRoll(TopologySpec grid)Roll is defined on Square and Hex, on one floor.
int DirectionCount(GridShape shape)Roll directions: 4 on Square, 6 on Hex, 0 elsewhere.
Vec2 Direction(Topology t, int dir)The way a roll direction points, in board units.
bool IsLegalStep(MazeData m, int from, int to, out string reason)Can a player step between two cells of the bare maze, ignoring gimmicks?
bool Validate(MazeData m, out string error)Is the data well-formed? Both sides of every opening agree, holes are sealed, every start, goal and gimmick sits on a playable cell, nothing overlaps, every gate has its switch, every tunnel runs straight under a corridor, and the stored route walks.
const int SwitchShift = 16Where the switch flips sit in MazePlay.Keys.

Solving and rating

MazeSolverWhat it does
MazeVerdict Solve(MazeData m, int stateBudget = 500_000)Solves the maze as it stands and returns a MazeVerdict: Solvable, Par, PlayerPars, Count, CountComplete, Unique, CanGetStuck, Explored, Path, Routes and Moves.
MazeVerdict SolveFrom(MazeData m, MazePlay play, int player = 0, int stateBudget = 500_000) Solves on from a position in play. Par is the moves still needed. On Step it solves for that player alone, and Moves holds the slot of each step.
int[] StepParsFromEveryCell(MazeData m, int player = 0, int stateBudget = 500_000) On Step, that player's par to its goal from every cell, holding nothing, with all the gimmicks (-1 for a hole or no way home). Null when the budget ran out.
const long CountCapThe best-solution count stops at 1,000,000,000.
Rating and checksWhat it does
MazeDifficulty.Score(MazeData m), MazeDifficulty.Stars(MazeData m)The raw score and the 1 to 5 stars. See How the stars work.
MazeAudit.Verify(MazeData m, out string before, out string after)Solves a stored maze again and restamps its verdict. True when anything changed.
MazeAudit.Reroll(MazeData m)A fresh maze from the same settings and a new seed, or null for a maze with no settings.
MazeAudit.MeetsRequest(MazeData m)Did the maze get everything its settings asked for: solvable, the target stars, the coverage, no soft-lock when asked, and a fair race?
MazeAudit.Short(MazeData m)One line, such as "par 63 steps, 3 of 5 stars, unique".

Presets and Auto

MemberWhat it does
MazePresets.AllEvery preset, in menu order. Each MazePreset has a Name (its menu path), a Description, and Make(), which returns a fresh MazeSettings.
MazePresets.Tune(MazeSettings s, List<string> changes)What the Auto button does: a copy with settings that fight each other fixed, and a line per change.

Pictures

MazeExport draws a maze in plain C#, so it works in a build, in the editor or on a server.

MemberWhat it does
byte[] Png(MazeData m, ExportOptions options = null)A PNG file's bytes.
string Svg(MazeData m, ExportOptions options = null)An SVG document.
byte[] Pixels(MazeData m, ExportOptions options, out int width, out int height)Raw RGBA bytes, top row first.
Png and Pixels with a MazeSketchA picture of a given moment, for example part way through the solution.
int FitSize(MazeData m, MazeSketch sketch, ExportOptions options, int maxWidth, int maxHeight) The Size that fits a box.
ExportOptionsDefaultWhat it does
StylePrintablePrintable (black on white with the start and goal), AnswerKey (with the solution drawn in), or AsShown (colour, every gimmick, the solution and a legend).
Size2048The maze's longer side in pixels (64 to 8192).
WallWidth0.12Wall thickness as a fraction of a cell (0.02 to 0.4).
Margin0.8The white border, in cells (0 to 4).
LegendtrueAsShown: draw the legend under the maze.
Floor-1Stacked boards: -1 draws every floor side by side, and 0 or more just that floor.

MazeSketch is the drawing model behind the pictures. MazeSketch.Build(maze, play, focus, trails) sketches a position, MazeSketch.Frames(maze) steps through the stored solution move by move, and MazeSketch.Describe(maze, cell, play) says what is in a cell in plain words.

Shapes

A ShapeMask is a black and white bitmap (Width, Height, Pixels, row 0 at the top). Set it on MazeSettings.ShapeMask with Shape = ShapeKind.Custom.

MethodWhat it does
ShapeMask.FromRows(params string[] rows)From rows of text: # (or any character other than a space or .) is inside.
ShapeMask.FromText(string text)Text in the built-in 5 by 7 font.
ShapeMask.FromPixels(byte[] rgba, int width, int height, bool bottomRowFirst, ShapeSource source, float threshold = 0.5f, int maxSide = 128) From a picture's RGBA bytes. Pass bottomRowFirst true for Unity's GetPixels32. The result is cropped to the shape and shrunk to at most maxSide across, and is null when nothing counts as inside.

Topology

A Topology is a grid as a graph of cells and slots. Get one from MazeData.Topology or Topology.Create(spec).

MemberWhat it does
int CellCount, int SlotCount(int cell)How many cells, and how many sides a cell has.
int Neighbor(int cell, int slot)The cell across a side, or -1 at the border.
int OppositeSlot(int cell, int slot), int SlotTo(int cell, int other)The neighbour's side that faces back, and the side between two cells (-1 when they don't touch).
Vec2 Center(int cell)A cell's centre in board units (x right, y up).
Edge EdgeOf(int cell, int slot)The wall on that side: a segment from A to B, or an arc when Arc is true.
int CellAt(Vec2 p)The cell under a point, or -1.
void Bounds(out Vec2 min, out Vec2 max)The board's bounds, for framing.
(int x, int y) Coord(int cell)Column and row, or index in ring and ring on a circular board.

A board with floors is a LayeredTopology, which adds Base, Floors, FloorOf(cell), BaseCell(cell), At(floor, baseCell), UpSlot(cell), DownSlot(cell) and IsStairSlot(cell, slot).

ScriptableObjects

TypeWhat it holds
MazePuzzleAssetOne maze: Maze and Label, plus shortcuts to its verdict (Shape, Floors, Movement, PlayerCount, Solvable, IsUnique, OptimalCount, Par, Difficulty, Seed) and Set(data, label).
MazePuzzlePackAn ordered list of mazes: PackName, Mazes, Count, Get(index) (null when out of range), Set, Add, Replace(index, data) and Clear().
PuzzleAssetsCreatePuzzle(data, label) and CreatePack(mazes, packName) make new instances in memory, which you can save with AssetDatabase.CreateAsset in the editor or use at runtime.
IPuzzleProviderBoth asset types implement it: AppendTo(List<MazeData> levels) adds their mazes in order, so one list in the inspector can take either.

Both are created by the Maze Generator's Save menu, not by an empty right-click Create.

Demo components

These are in SimpleMaze.Demo. The Demos page explains how they fit together.

TypeWhat it does
MazeDemoThe one component the demo scene needs. It builds the view, game, HUD, hub, sounds and effects in code and runs the flow. Fields: Camera, Pitch, HdrpLook, UiThroughCamera and a level pack per mode. Methods include Setup(), PlayEndless(mode, grid, stars), PlayLevel(mode, index), Generate(mode, settings), Begin(maze), NextGame() and BackToHub().
MazeGamePlays a maze on a MazeView3D: input, movement, every gimmick's animation, moves against par, undo, restart, hints, auto-solve, players and races, stairs and the camera. Start a game with Begin(maze), drive it with Push(Vector2 screen) or the keyboard, and listen to Won, Cue, Moment and Message.
MazeView3DBuilds a maze in 3D from primitives and meshes, on any grid, with no prefabs: Build(maze), CellPosition, StandPosition, FocusFloor, FrameCamera, and lists of the objects it made (keys, doors, gates, players and so on).
MazeHudThe in-game HUD and win panel, in uGUI with the built-in font.
MazeHubThe front screen: the welcome panel, the mode cards, and each mode's Endless and Level Pack setup.
MazeMode, MazeModesThe five demo modes, their names, colours, sample mazes and the Endless recipe for each mode, grid and star count.
MazeProgressEach pack level's best moves, kept in PlayerPrefs: Best, Record, Clear and NameOf.
MazeBeeperSounds made in code for every MazeCue, with no audio files.
MazeEffectsSmall effects (sparkles, dust, confetti) from a pool of primitives, for every MazeMoment.
DemoLook, DemoHdrpThe demo's colours and materials for the active render pipeline, and the HDRP volume that gives it the same look.

Building blocks

The pieces the generator is made of are public too, for anyone who wants to build their own pipeline. Most projects never need them.

TypeWhat it does
MazeBuilderBuild(settings, seed) makes one maze from clamped settings and an exact seed, which is what every MazeGenerator method calls.
PassagesThe open sides of every cell over a topology, plus holes, with Open, Close, IsOpen, Degree and OnRim.
CarverCarves a perfect maze through every playable cell with a CarveAlgorithm.
HolePlacer, BoardShape, Weave, GimmickPlacerHoles, shapes, crossings and gimmicks.
GraphSearchBreadth-first search, shortest paths and connectivity over passages.
RngThe small deterministic random generator, seeded from a string.