Why RuneGrid Validates Levels
Generating a puzzle is only half the problem.
A procedural system can easily create grids that are technically correct but unpleasant to play: puzzles with too little information, accidental ambiguity, or clue layouts that encourage guessing rather than deduction.
RuneGrid therefore treats validation as a distinct stage of generation.
The generator is allowed to experiment freely, but every puzzle must survive a series of structural checks before it can become a playable level.
Correctness is not enough
At the lowest level, RuneGrid verifies that a generated table is mathematically valid.
static func isValidGroupTable(_ table: [[Int]], identity: Int) -> Bool {
let size = table.count
for row in 0..<size {
if Set(table[row]) != symbolSet { return false }
}
for col in 0..<size {
let columnValues = Set((0..<size).map { table[$0][col] })
if columnValues != symbolSet { return false }
}
...
}
Each symbol must appear exactly once in every row and column, and the operation must satisfy associativity.
This ensures the puzzle genuinely represents a finite group structure rather than merely resembling one.
But mathematical validity alone does not produce a satisfying puzzle.
Clues need structure
A puzzle may be solvable while still feeling arbitrary.
RuneGrid therefore measures the quality of its clue layout, not just the number of clues.
struct ClueQuality {
let fixedCount: Int
let identityRowClues: Int
let identityColumnClues: Int
let nonSelfInverseClues: Int
let nonAbelianWitnessClues: Int
let distinctRowsTouched: Int
let distinctColumnsTouched: Int
}
The validator asks questions such as:
- are clues spread across enough rows and columns?
- does the player see enough of the identity structure?
- are non-abelian behaviours visible?
- are there enough footholds for deduction?
This matters because RuneGrid is trying to guide attention, not merely hide information.
Identity clues act as anchors
The identity row and column are especially important early in a solve.
guard quality.identityRowClues >= 1 else { return false }
guard quality.identityColumnClues >= 1 else { return false }
These clues often provide the player’s first stable reference points.
Without them, a puzzle may still technically solve correctly, but the player’s reasoning process becomes much less intuitive.
The validator protects against this by ensuring that some structural anchors survive clue pruning.
Non-abelian groups need witnesses
Some groups behave differently depending on order.
RuneGrid calls these non-abelian witnesses:
let nonAbelianWitnessClues = fixedPositions.filter {
$0.row != $0.col &&
level.solution[$0.row][$0.col] != level.solution[$0.col][$0.row]
}.count
These clues quietly expose asymmetry in the table.
Without them, a non-abelian puzzle can accidentally feel indistinguishable from a simpler commutative structure.
The validator therefore ensures that enough of these asymmetries remain visible to the player.
Validation protects against accidental frustration
One of the simplest but most important checks is uniqueness.
static func hasUniqueLatinCompletion(
clues: [[PuzzleCell]],
size: Int,
limit: Int = 2
) -> Bool
The validator searches for multiple valid completions.
If more than one solution exists, the puzzle is rejected.
This prevents situations where a player makes perfectly logical deductions but still arrives at an ambiguous board.
For a puzzle game built around structure and inference, uniqueness is essential.
Procedural systems need boundaries
The validator exists because procedural generation is powerful but careless.
A generator can produce enormous variation very quickly, but without constraints it also produces:
- noise
- unfairness
- ambiguity
- dead ends
- accidental difficulty spikes
Validation acts as a counterweight.
It keeps the puzzle space broad while preserving a coherent solving experience.
The invisible design layer
Ideally, players never consciously notice the validator.
They simply experience levels that feel:
- fair
- readable
- varied
- intentional
That invisible layer is important.
RuneGrid is not trying to generate chaos. It is trying to generate structured discovery.
Validation is one of the systems that keeps those two things separate.