View: Multi-Page Single Page

Install & requirements

Import the package. The Core (generation / solving / analysis / data / ScriptableObjects) has no package dependencies and works in any render pipeline.

The demo and editor tooling use the Input System and TextMeshPro packages — Unity prompts to import TMP essentials the first time. The demo board is built from runtime primitives tinted via MaterialPropertyBlock, so it renders in Built-in, URP, and HDRP without material conversion. Requires Unity 6000.3+.

Assembly definitionsCore, Demo, and Editor are separate asmdefs, so the generator never pulls in the demo's packages.

No-code start

1

Open the generator

Window ▸ Living Failure ▸ Simple States ▸ Puzzle Generator.

2

Pick a mode

Classic (find the combination), Ordered (find the order), Lights Out (flip the grid), or Trilight (three states — off, dim, bright). Set states and switches (3–8) or the grid size (up to 56 cells), then pick a Preset — or dial in solution style, decoys, traps, and rule shape yourself. On the grid modes, pick a Goal: All Lit, All Dark (blackout), or Pattern — click-paint the target shape right in the window. Auto tunes classic settings to a verify-friendly shape.

3

Generate

Click Generate (or a batch — the set accumulates, with an Only unique filter). The full analysis appears on the right: verdict, best solution, path preview, readable rules, switch roles, diagnostics, and the rule matrix — or the board grid for Lights Out.

4

Save

Save ▸ Current (one puzzle asset), Pack (all), or Pack (unique only) — a native Save dialog picks the location. The demo's four pack slots take packs, not single-puzzle assets — even a pack of one.

5

Play

Open Scenes/DemoScene, assign one pack per mode on the StatesDemo component, and press Play.

Code start

using SimpleStates;

var settings = new GenerationSettings {
    Mode = PuzzleMode.Classic,
    StateCount = 6, SwitchCount = 6,
    SolutionStyle = SolutionStyle.Single,  // exactly one valid combination
    DummyPolicy = DummyPolicy.Allow,       // decoy switches allowed
    MinSolutionSize = 2, MaxSolutionSize = 4,
    Seed = "level-42",                     // deterministic — same seed, same board
};

StatesPuzzle puzzle = ClassicGenerator.GenerateVerified(settings);
// puzzle.Solvable, puzzle.Unique, puzzle.Difficulty (1–5)
// puzzle.Analysis.ShortestSolutions[0], .RequiredSwitches, .DummySwitches …

Ordered chains with traps

var ordered = new GenerationSettings {
    Mode = PuzzleMode.Ordered,
    StateCount = 8, SwitchCount = 8,
    SolutionStyle = SolutionStyle.Few,
    DummyPolicy = DummyPolicy.Require,     // traps count as decoys, so allow them
    TrapPolicy = TrapPolicy.Require,       // wrong presses turn states back off (always recoverable)
    MinSolutionSize = 4, MaxSolutionSize = 6,
    MaxAttempts = 800,
};
StatesPuzzle chain = OrderedGenerator.GenerateVerified(ordered);

Lights Out grids (with pattern goals)

var lights = new GenerationSettings {
    GridWidth = 5, GridHeight = 5,         // a grid implies Lights Out
    MinSolutionSize = 6, MaxSolutionSize = 14,
    GoalMode = LightsOutGoal.Pattern,      // or AllLit (default) / AllDark (blackout)
    GoalPattern = 0b00100_01110_11111_01110_00100,   // a diamond (bit y*W+x = lit)
};
StatesPuzzle grid = LightsOutGenerator.GenerateVerified(lights);
// grid.Analysis.ShortestSize == the true minimum number of presses (the par)

Trilight (mod-3) grids

var tri = new GenerationSettings {
    GridWidth = 5, GridHeight = 5,
    MinSolutionSize = 6, MaxSolutionSize = 14,
};
StatesPuzzle triBoard = Mod3Generator.GenerateVerified(tri);
// triBoard.CellStart[i] / CellGoal[i] hold 0..2; solutions list a cell TWICE
// when it needs two presses, so playback and par need no special cases.

Playing a puzzle

The demo's StatesGame (in SimpleStates.Demo) runs any generated or saved puzzle end to end — board build, presses, gates, win detection:

using SimpleStates.Demo;

game.LoadLevel(puzzle);     // builds the 3D board
game.PressSwitch(2);         // press P3 (classic toggles; ordered checks its gate)
game.ResetLevel();
game.StartAutoSolve();      // plays the best solution one press at a time
// events: LevelLoaded, LevelReset, LevelSolved, Pressed, PressBlocked

Or skip the demo entirely — a classic puzzle is just XOR over bitmasks: state ^= puzzle.ClassicRules[switch], solved when state == puzzle.Goal. Ordered rules carry explicit conditions and effects. ClassicSolver.Analyze / OrderedSolver.Analyze recompute the full analysis anywhere, editor or runtime.

TipTo see it wired end to end, open the demo scene (Demos) and read StatesGame + StatesLevelRenderer — the whole play loop is four small components.

Next steps