Article
How a Puzzle Generator Proves Its Own Answers Are Correct
Sudoku, maze, crossword and word search generators can each go wrong in a different way. Here is exactly what our code checks before a puzzle is allowed to print.
Every generator on this site runs entirely in your browser, and every one of them could, in principle, hand you a page that cannot actually be solved, or one that looks solved but isn’t. A Sudoku with two valid completions. A maze with a wall sealing off the finish. A crossword entry floating away from the rest of the grid, connected to nothing. A word search whose answer key marks the wrong copy of a three-letter word. None of these are exotic bugs. They are the default outcome of the straightforward version of each algorithm, which is why “the puzzle didn’t actually work” is such a common complaint about free puzzle sites in teacher and parent forums.
This is a walk through what our Sudoku, maze, crossword and word search generators actually do, in code, before a PDF is built — and honestly, where that checking still has edges.
Why a printed puzzle is harder to trust than a solved one
An online puzzle can be wrong and nobody notices, because the same page that generated it can also grade it. A printed puzzle has no such safety net. Once it’s on paper, the only proof that it works is whatever checking happened before it was exported. If a generator skips that step, a flawed puzzle looks identical to a good one right up until a student gets stuck on a route that doesn’t exist, or a parent grading homework finds an answer key that contradicts the grid.
The four generators on this site have almost nothing in common under the hood — a Sudoku solver, a maze’s graph search, a crossword’s placement heuristics and a word search’s grid scanner are different problems entirely. What they share is a design rule: never trust the step that placed something to have placed it correctly. Build the finished puzzle, then make it prove itself, using a second, independent check that reads the result the way a solver would — before the layout code is allowed to turn it into a page.
Sudoku: the search that looks for a second answer before the first one ships
A Sudoku puzzle is generated backwards. The code first builds a complete, valid grid — makeSolution shuffles bands, stacks and symbols of a base Latin square so the full board is different every time — and only then starts removing digits to create the puzzle. Removing a digit is the only thing that can break a Sudoku, and it can only break it one way: because the starting grid is already a full solution and clues are only ever taken away, never changed, the puzzle can never end up with zero solutions. The original grid is always still a valid completion. The only failure mode possible is ending up with more than one.
That is exactly what the code checks for, cell by cell. Before a digit is permanently removed, countSudokuSolutions runs a backtracking solver against the grid with the digit missing, using a minimum-remaining-values heuristic to pick the most constrained empty cell first. It doesn’t try to find every solution — it stops the instant it finds a second one. If a second solution exists, the digit goes back in and that cell stays a clue. The generator works through cells in mirrored pairs first, to aim for the symmetric look Sudoku is traditionally published with, then falls back to single cells wherever symmetry would stop it short of the target number of clues — the code’s own comment is blunt about the priority: hitting the intended difficulty matters more than a decorative pattern.
Difficulty itself comes from a second, separate solve. rateSudoku solves the finished puzzle using only human techniques — filling in forced single candidates, then hidden singles, and only falling back to guessing (with backtracking) when logic alone stalls. It counts how often each technique was needed and how deep any guessing had to go, turns that into a score, and buckets the score into easy, medium, hard or expert. The label on your PDF describes the solving path the puzzle actually requires, not a lookup table.
Two gates apply here, not one: the same uniqueness check that ran during carving runs again in the export code, right before pages are built, and throws rather than exporting if anything looks off. It’s worth remembering that a low clue count on its own proves nothing — the mathematically proven minimum for any unique 9×9 Sudoku is 17 givens, and grids with far more clues than that can still have two solutions if the wrong ones are removed. Clue count is not the check. The solver run is.
Maze: nothing gets printed until a solver walks it first
Maze generation and maze solving are kept as two separate pieces of code on purpose, and the comment above the solver says so directly: “every maze is checked after carving and again before export.” Carving uses a randomized depth-first walk over an adjacency list — from the start cell, it picks an unvisited neighbor, knocks down the wall between them, and keeps going, backtracking along its own path when it runs out of new cells. Circular mazes use the same walk over a graph where each ring wraps around like a wheel’s spokes.
That carving process is supposed to produce what’s called a “perfect maze”: every cell reachable, no loops, exactly one route between any two points. The code does not simply assume the carve succeeded. solveMaze runs a plain breadth-first search from start to finish over the resulting graph and returns the path it finds, or an empty path if the finish is unreachable. verifyMaze then checks that path is real — not just that a route exists, but that every consecutive step in it is an actual edge in the maze — and generateMaze additionally confirms every single cell was visited during carving, not only that start and finish happen to connect. If any of that fails, generation throws immediately rather than returning a maze. The same solver runs again, independently, right before the PDF layout is built, and blocks export if a maze somehow fails a second look.
Crossword: a word that cannot cross anything else is not printed
The crossword generator places one entry at a time onto an empty grid, and every entry after the first is only allowed onto the grid if it crosses a letter that’s already there. This is checked directly in validateCandidate: a candidate position is rejected if it runs off the grid, if the cell just before or after the word is already occupied (which would silently merge it into another word’s run), if an overlapping cell holds a different letter, or if a cell next to the new word — but not crossing it — is already filled, which would let two answers touch edge-to-edge without actually intersecting. After all of that, one rule decides whether the placement counts: if it doesn’t cross at least one existing letter, it’s rejected outright. A word with no legal crossing position anywhere on the grid is never placed. It goes into the puzzle’s unplaced list, and the interface reports it by name rather than quietly leaving it off the page — the tool’s own copy calls this out: isolated answers are rejected, not dropped.
The generator tries up to 72 randomized layouts per puzzle and keeps whichever one placed the most words with the most crossings in the smallest area, which is also why the same word list can produce a noticeably different grid shape each time you reshuffle the seed. Across and Down numbering isn’t assigned by hand or by convention lookup — after the best layout is chosen, the code collects every distinct cell where an entry starts, sorts those coordinates in reading order (top row to bottom, left to right within a row), and numbers them in that order. A cell where an Across and a Down entry both begin gets one shared number, exactly as it should. If the best attempt still manages to place fewer than two crossing entries, the generator gives up and returns an empty grid rather than exporting a sparse, disconnected page.
Word search: checking what the grid actually says, not what the word list asked for
The riskiest moment in a word search generator is the one that seems most harmless: filling the leftover blank cells with random letters after every word has been placed. A three- or four-letter word can spell itself out by pure coincidence in that noise, in a spot that has nothing to do with where it was actually placed — and a naive generator has no way to notice, because it only ever checks its own placement records, never the letters it actually printed.
This code checks the letters it actually printed. After filling the blanks, it rescans the entire finished grid, in all eight directions regardless of which directions the puzzle allows a solver to use — the code’s own reasoning is that a solver’s eyes aren’t limited by the settings — looking for every place each placed word’s letters appear. Any occurrence that isn’t the word’s own recorded position gets treated as a defect: one of its randomly-filled cells is re-rolled to a different letter, and the whole grid is rescanned again. That repair loop runs for up to 400 rounds, which in practice is enough to clear nearly every accidental duplicate. The one case it can’t fix is a duplicate made entirely of other placed words’ letters rather than filler — for example a short word whose letters are completely contained inside a longer one on the same list, forward or backward. No amount of re-rolling filler can fix that, because none of the conflicting letters are filler; the model catches this earlier, at the word-list stage, and warns about it directly rather than pretending the grid can be repaired.
There’s a second, independent scan after generation finishes: verifyPuzzle looks up every placed word’s real occurrences on the finished grid one more time and reports two distinct problems — a word missing from where it should be, or a word findable in more than one place. This is the one check among the four generators that doesn’t hard-block the PDF export function itself; it surfaces as a named, specific warning banner in the tool before you download, rather than a thrown error inside the file-building code. The check is real and runs against the actual grid, not the word list — it just leaves the final call to the person using the tool.
Four generators, four ways to be wrong, four checks that catch them
| Puzzle | What can go wrong silently | What actually checks for it | Where the check runs |
|---|---|---|---|
| Sudoku | Two or more valid completions for one printed grid | A backtracking solve that stops as soon as it finds a second solution | Every clue removal, then again right before export |
| Maze | A wall or rendering mismatch seals off the finish | A breadth-first search from start to finish, checked edge by edge | Right after carving, then again right before export |
| Crossword | An answer that touches the grid without crossing anything | A placement rule that rejects any word with zero crossings | At the moment each word is placed |
| Word search | A word appears twice — once placed, once by accident | A full 8-direction rescan of the finished letter grid | After filling, and again as a warning before download |
What a classroom actually experiences when a check like this is skipped
None of this is abstract. A Sudoku with two solutions doesn’t announce itself — a student who fills it in correctly by one valid logic path gets marked wrong against an answer key that only shows the other one. An unverified maze doesn’t look broken on the page; a child works every branch, finds every path sealed, and concludes they failed at something that was never solvable. A crossword with a touching-but-not-crossing pair of answers lets a student fill in one entry exactly as clued, only to find it contradicts a neighboring word at a shared edge that was never supposed to be shared. A word search with an accidental duplicate produces two children circling two different, equally correct locations for the same word, and an answer key that can only agree with one of them.
In every case the person holding the paper has no way to know the puzzle is at fault. That is precisely why the check has to happen before printing, not after a complaint.
Where automatic verification still has edges
None of this is free, and it isn’t infallible. Checking costs generation time: Sudoku tries up to ten full generate-and-carve cycles to hit a target difficulty, the crossword tries up to 72 candidate layouts, and the word search allows up to 24 placement attempts plus 400 rounds of letter repair. On a demanding request — an expert word list packed close to the grid’s capacity, for instance — the generator can still come back honest but short of ideal, reporting a word it couldn’t place rather than looping forever trying to force one. The uniqueness and solvability checks themselves are not probabilistic; a Sudoku solve either finds a second solution or it doesn’t, and a maze’s breadth-first search either reaches the finish or it doesn’t. What is a judgment call is the Sudoku difficulty rating, which is a heuristic built from one particular model of human solving order — it’s a reasonable proxy for how much logical work a puzzle demands, not a guarantee of how hard any one person will find it.
If you’re comparing this against a generator you’ve used before, the fastest way to see the difference is to try the same word list or grid size on our word search maker or crossword maker and read the warnings it gives you — a tool that tells you a word didn’t fit is doing more, not less, than one that says nothing and hopes. For more on how this site approaches printing accuracy generally, see why Printable Toolkit exists and our printing guide for getting a PDF onto paper at true size. The full set of generators, including these four, is listed on the puzzles page.