Any system generating playable content — levels, boards, puzzles — can produce something unsolvable. The player does not experience that as difficulty. They experience it as a broken game, and they are right.
Generate, then verify, then ship
The reliable pattern is to treat generation as a proposal and verification as the gate. Generate a candidate, prove it solvable, and only then let it reach a player. Anything that fails verification is discarded and regenerated.
The proof depends on the genre:
- Puzzle with a known solver. Run the solver. If it finds a solution, the level is finishable, and the solution length gives you a difficulty measure for free.
- Path-based. Flood fill or A* from start to goal. If no path exists, the level does not exist.
- Resource-based. Check that required resources are reachable in an order that satisfies the dependencies.
- Board games with deals. Verify that no deal creates an immediately dead board — the most common failure in block and tile games.
Difficulty is the second problem
Solvable is necessary, not sufficient. A level solvable only by a twenty-move sequence nobody would find is technically fine and practically broken. The solver's output — moves required, branching at each step, how many wrong paths look right — is what turns "possible" into "appropriately hard".
Verify in the build, not in the design document
Run the check as an automated test over a large sample of generated content, as part of the build. A generator that was correct last month and is not now is exactly the kind of regression that reaches players, because nothing crashes.
This is what we do day to day — game, app and website QA at Factorial Studio.