View: Multi-Page Single Page

Generating

Every setting, what it changes, and how the generator keeps its promises.

The Maze Generator window

Open Window > Living Failure > Simple Maze > Maze Generator. The settings are on the left in six sections (Board, Carving, Shape, Players and movement, Gimmicks and Quality), and the mazes you've made are on the right with the analysis pane. Fields only appear when they apply, so Rings shows for a circular board and Width and Height for the others.

Every maze the window makes goes through verified generation: if a maze misses what you asked for, the generator tries the next seed, and if none of its tries succeed it gives you the closest one with a note saying why. Generation runs on a background thread with a progress bar and a Cancel button, and your settings and the unsaved mazes survive a recompile.

Each table below gives the label in the window, the matching field on MazeSettings for code, and the range it accepts. Values outside the range are clamped, so code can pass anything.

Board

SettingFieldRangeWhat it does
GridGrid.ShapeSquare, Hex, Triangle, CircularThe cell shape. Square cells have 4 sides, Hex 6 (pointy-top), Triangle 3 (alternating up and down), and Circular is a centre cell inside rings.
Width, HeightGrid.Width, Grid.Height2 to 64Cells across and rows (on Triangle, Width counts triangles per row).
RingsGrid.Rings2 to 40Circular only: the rings around the centre cell, which is the board's radius. Rings split into more cells as they grow, so cells stay roughly square from the centre to the rim.
First ring cellsGrid.FirstRing0, or 3 to 12Circular only: the cells in the first ring. 0 means automatic, which is 6.
FloorsGrid.Floors1 to 8Stack the board into floors joined by stairs. Every floor has the same outline and holes, and each is carved as its own maze.
Stairs per floorStairs1 to 4Stairs between each pair of floors. The first goes where that floor's maze is farthest from the stairs you arrived by, so every floor gets crossed, and each extra one adds a loop.

In code, TopologySpec.Grid(shape, width, height) and TopologySpec.Circle(rings) build the board, and you set Floors on the result.

Carving

SettingFieldRangeWhat it does
AlgorithmAlgorithm6 choicesHow the maze is carved. Each one has its own look: Recursive Backtracker makes long winding corridors, Prim short and bushy ones, Kruskal an even, patchy maze, Wilson a perfectly uniform one, Hunt and Kill long corridors with fewer dead ends, and Growing Tree anything in between.
BranchinessBranchiness0 to 1Growing Tree only: 0 gives long winding corridors and 1 short, bushy ones.
BraidBraid0 to 1Dead-end removal. 0 is a perfect maze, with exactly one route between any two cells, and 1 leaves no dead ends at all. Rolling mazes need some braid, because rolling needs loops.
Extra loopsLoops0 to 200 in the window, up to 999 in codeRandom openings, each adding a second way round.
RoomsRooms0 to 12Open rooms carved into the maze, spread out.
Room sizeRoomSize1 to 4How far each room reaches from its centre, in cells.
HolesHoles0 to 0.35The fraction of cells removed as holes. The board always stays in one piece.
Weave crossingsWeave0 to 40Square boards only: places where a passage tunnels under a corridor, like the bridges in a printed weave maze. The maze keeps its routes and just gains crossings.

Shape

SettingFieldRangeWhat it does
ShapeShapeNone, Circle, Ring, Heart, Star, Diamond, Cross, Text, CustomCuts the board to an outline. It works on every grid.
TextShapeTextA to Z, 0 to 9, space, - ! ? . + and <3 for a heartShape Text: the word, in the built-in 5 by 7 font. Give it a wide board, about 6 cells across per letter and at least 9 rows.
Image, or Mask rowsShapeMaskany picture, or rows of # and .Shape Custom: drop in any picture and choose whether its Dark, Light or Opaque areas are inside the maze, where the line falls, and how much Detail to keep (24 to 160 mask pixels across). The picture needs no import settings. Leave the image empty to type the shape as rows instead, top row first.
FillShapeFill0.3 to 1How much of the board the shape fills.
Connect piecesConnectPieceson or offWhen the shape falls apart into pieces, like the letters of a word, join them with the shortest bridges. Off keeps only the largest piece.

Players and movement

SettingFieldRangeWhat it does
MovementMovementStep, RollStep moves one cell at a time on every grid. Roll slides in a straight line until something stops it, on one-floor Square and Hex boards only. Anywhere else a Roll maze uses Step, with a note.
Start / goalEndpointsFarthest, Center Out, Outside In, FixedFarthest puts them at the two cells farthest apart along the maze. Center Out starts in the middle with the goal on the rim, and Outside In is the other way round. Fixed uses the two cells you give.
Start cell, Goal cellStart, Goalcell indicesFixed only. If they aren't two different playable cells, the farthest pair is used instead, with a note.
Open borderOpenBorderon or offCuts an entrance and an exit in the outer wall where the start and goal touch it, for printed mazes. With Farthest, both are then picked on the border.
PlayersPlayers1 to 4How many players are on the board.
Shared goalSharedGoalon or offWith several players: on gives everyone one goal (the centre, or the Fixed goal) from fair starts, which makes it a race. Off gives each player a goal of its own.

Fair races. On Step, a race's starts are picked so that every player's par is exactly the same. With gimmicks, each player has to fetch its own keys and gems, so the other players' starts are chosen after the gimmicks are placed, using each cell's real par. When a board has no fair starts, a "Players:" note says so, MazeData.Fair is false, and verified generation tries the next seed.

How players move

The solver, the generator and the play rules your game uses all follow the same rules, so a move your game allows is exactly a move the solver counted.

Step. A player moves one cell through an open side. A door needs its key, a shut gate blocks, a one-way side only lets you out its own way, a tunnel side leads under the corridor to the cell beyond, and stairs lead up or down a floor. A trap is never a legal step. Stepping into a portal puts you on its twin. Keys and gems are picked up where you land, and landing on a switch flips every gate of its colour. You are home when you land on your goal holding every gem. With several players, each one moves on its own and keeps its own keys, gems and switch flips, and players can pass through each other.

Roll. Every player rolls the chosen way at once, front-most first, until a wall, a locked door, a shut gate, a one-way side, the border or another player stops it. Tunnels are rolled straight through. Rolling onto a trap fails the whole roll, so nothing changes. A player picks up whatever it rolls over, and the players share keys and gems, which makes several rolling players a cooperative puzzle. A player is home the moment it rolls over its goal holding every gem, a portal throws it out of its twin still rolling, and a player that comes to rest on a switch flips its gates once the roll is over.

Gimmicks

Gimmicks are placed one type at a time in a fixed order (portals, keys and doors, switches and gates, gems, one-way sides, then traps), and the maze is solved again after each type. A type that can't be made to work is dropped on its own, with a note, and never drags the others down.

SettingFieldRangeWhat it does
Keys and doorsKeys0 to 6Each door locks a side on the way to the goal, and its key waits somewhere you can reach before that door, off the way and as far from it as possible.
SwitchesSwitches0 to 4Each switch has its own colour, and landing on it flips every gate of that colour between open and shut. Its first gate is shut across the way, and the switch waits before it.
Gates per switchGatesPerSwitch1 to 3The extra gates are decoys off the way. Some start open, and the switch shuts them.
Shortcut doorsShortcutDoorson or offOff (the default) puts every door and every switch's first gate truly in the way, so its key or switch is always needed. A maze with lots of loops may then get fewer doors, with a note. On lets doors and gates go where a player could walk around them, so the key opens a shortcut instead of the only way.
GemsGems0 to 8Every gem must be collected before a goal lets a player in. They go in dead ends first, spread out.
TrapsTraps0 to 0.25The fraction of free cells off the way that become traps. They sit beside the way as decoys, never on the way to anything you need.
One-way sidesOneWays0 to 24About half go along the way, so there's no going back, and the rest are decoys.
Portal pairsPortals0 to 4Pairs the best solution actually uses, so each one shortens the way, with the two ends far apart.
No soft-locksNoSoftLockson or offOnly accept mazes where no player can ever reach a position it can't finish from. It's off by default, because rolling mazes very often have such positions (like ice puzzles, give players a reset). Every maze reports it in CanGetStuck either way. On Roll boards it works best with Braid near 1.

When fewer doors, gates or portals fit than you ask for, you get fewer, with a note. As a rule of thumb, about one key or switch fits per 40 cells, and Auto lowers the count to that for you.

Quality

SettingFieldRangeWhat it does
Target difficultyTargetDifficulty0 to 5Keep trying mazes until one rates exactly this many stars. 0 accepts any rating. A miss returns the closest maze and says so in its notes.
Min coverageMinCoverage0 to 0.9The best solution must pass through at least this much of the maze. Gimmicks are also placed to make the player roam as much as they can.
Max attemptsMaxAttempts1 to 500Under Advanced: how many mazes to try for each result before falling back to the closest one.
State budgetStateBudget1,000 to 5,000,000Under Advanced: how many positions the solver may explore before it reports the maze as not verified. Several rolling players need more.

How the stars work

The rating comes from a score. On Step the score is the longest player's par, plus 5 for every real decision on the way (a fork whose wrong way runs 3 or more cells deep, so you can't see the dead end at a glance), plus 6 per key, 2 per gem or portal pair and 1 per one-way side. On Roll it is the par in rolls, plus 2 per key and 1 per gem.

StarsStep scoreRoll score
1up to 50up to 3
251 to 854 to 7
386 to 1268 to 11
4127 to 17912 to 22
5above 179above 22

The bands were measured on a sweep of everyday mazes (576 Step and 288 Roll boards, on every grid, sizes 6 to 24, all six algorithms, with and without braid and holes), so each star covers about a fifth of them. A maze that isn't proven solvable gets 0 stars. Bigger boards usually rate higher, so to hit a target, pick a board size that can reach it.

Auto and presets

Auto fixes settings that fight each other and tells you what it changed. In code it is MazePresets.Tune. It:

  • switches Roll to Step on a grid that can't roll (Triangle, Circular or stacked floors);
  • raises Braid to 0.6 on a Roll maze below 0.5, or to 0.9 when No soft-locks is on;
  • turns Weave off on a board that isn't Square;
  • lowers keys and switches to about one per 40 cells;
  • raises the State budget to 2,000,000 for several rolling players;
  • raises Max attempts to 150 for 4 or 5 star targets, coverage targets or No soft-locks.

Presets replace every setting with a ready-made recipe. In code they are MazePresets.All, and each one's Make() gives a fresh MazeSettings.

PresetWhat you get
Classic/Square 15×15A plain perfect maze.
Classic/Circular 10 ringsThe polar maze: start on the rim, finish in the centre.
Classic/Hex 13×13Honeycomb cells, six ways out of each.
Classic/Triangle 21×10Alternating triangles, three sides each.
Classic/Printable 30×30Big, with an entrance and an exit cut in the outer wall.
Shapes/Heart (circular)A circular board cut to a heart.
Shapes/Star (hex)A hex board cut to a star.
Shapes/Word: MAZEThe board is the word, and its letters are joined by bridges.
Shapes/Ring with roomsA circular ring with open rooms to cross.
Gimmicks/Keys and doorsThree locked doors on the way, each with its key hidden before it, and gems to collect.
Gimmicks/Switches and gatesShut gates on the way, opened by switches, and decoy gates the switches shut.
Gimmicks/Traps and one-ways (hex)Traps beside the way, and one-way sides you can't go back through.
Gimmicks/Portal hop (circular)Portal pairs and gems on a circular board. It asks for 3 pairs, and often fewer fit on this board, which its note tells you.
Roll/Ice board (square)Roll until a wall stops you, rated 3 stars.
Roll/Co-op pair (hex)Two players roll together, each to its own goal.
Players/Race of 4 (hex)Four players and one goal in the middle, with exactly equal routes.
Players/Duel (circular)Two players race to the centre.
Big/Weave 20×20Corridors crossing over and under each other.
Big/Tower of 3 floorsThree floors joined by stairs, with the goal on the top floor and a key and a switch on the way.

Seeds, batches and saving

The same settings and the same seed always give the same maze. In the window, Random uses a fresh seed for every Generate and shows the one it used. Turn Random off to type a seed and keep it. Each maze gets its own seed, the batch's seed followed by a dash and the maze's number in the set (-0, -1 and so on), and every maze stores its own seed, which the analysis pane can copy.

Verified generation tries the seed itself first, then the same seed with #1, #2 and so on added, until a maze meets the request. A maze's stored seed is the one that worked, such as level-7-0#15, so it always reproduces that exact maze.

Batch count makes 1 to 20 mazes per click and adds them to the set. Clear on generate empties the set first, so each click replaces the batch. Save then writes Current as a MazePuzzleAsset, or Pack (all) or Pack (unique only) as a MazePuzzlePack, using the name in Save name as the suggestion.

Limits and notes

The generator never quietly gives you less than you asked for. Whenever it adjusts something, the maze's Notes say what happened, and the Generation report in the analysis pane lists them. Each note starts with the setting it is about, for example "Rooms:", "Players:" or "Target difficulty:". Common ones:

  • Not enough room: rooms, loops, crossings, players, portal pairs or doors that wouldn't fit on the board.
  • A gimmick dropped: no layout with it could be solved (without a soft-lock, if you asked for that) in 8 tries, so it was left out.
  • A setting that doesn't apply: Roll on a board that can't roll, or Weave off Square.
  • A shape that's too small for the board, so the whole board was used.
  • A missed target: no maze in the attempts rated the stars you asked for, and you got the closest.
  • Not verified: the solver's state budget ran out before every player got home.

Use MazeAudit.MeetsRequest(maze) to check whether a maze got everything its settings asked for. A pack's inspector can re-roll every maze in the pack that didn't (Re-roll > Fallbacks).

Generating from code

Everything the window does is available from code through MazeGenerator. Your settings object is copied and clamped first, so it is never changed.

using SimpleMaze;

var s = new MazeSettings
{
    Grid = TopologySpec.Grid(GridShape.Hex, 13, 13),
    Players = 2,
    SharedGoal = true,
    Keys = 1,
    Gems = 2,
    TargetDifficulty = 4,
    Seed = "level-7",                 // empty = a fresh random seed
};

MazeData one = MazeGenerator.Generate(s);          // one maze from this exact seed, solved and rated
MazeData good = MazeGenerator.GenerateVerified(s); // tries seeds until the maze meets the request
List<MazeData> pack = MazeGenerator.GenerateBatch(s, 10);   // seeds level-7-0 to level-7-9, each verified

Each one has an Async version that runs on a background thread and takes a CancellationToken. In Unity, await carries on on the main thread afterwards. GenerateBatchAsync also reports progress:

var progress = new Progress<int>(n => Debug.Log($"{n} of 10 done"));
List<MazeData> mazes = await MazeGenerator.GenerateBatchAsync(s, 10, progress, cancel.Token);

A custom shape comes from ShapeMask.FromRows, ShapeMask.FromText or ShapeMask.FromPixels, which reads raw RGBA bytes, so set Shape = ShapeKind.Custom and ShapeMask on the settings:

s.Shape = ShapeKind.Custom;
s.ShapeMask = ShapeMask.FromRows(
    "..##...##..",
    ".####.####.",
    "###########",
    ".#########.",
    "..#######..",
    "....###....");

See the API Reference for everything on MazeData.