Sudoku looks simple, but checking whether a puzzle is valid, has one solution, or is genuinely difficult turns out to be more complicated than it first appears.
I wanted a small tool that could answer a few basic questions without relying on a server or external libraries. Everything runs directly in the browser as a static page.
This post walks through how the analyzer works and why a few design choices mattered.
Puzzle input
The tool accepts a single 81 character string.
Digits 1 to 9 represent givens.
Dots or zeros represent blanks.
Example input:
4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......
This format is common, compact, and easy to share, which makes it practical for links and testing.
Validity checking comes first
Before doing anything, the grid is checked for basic Sudoku rule violations.
Each row, column, and 3 by 3 box is scanned for duplicate values using simple sets.
function isValidGrid(grid) {
const seen = new Set();
for (let r = 0; r < 9; r++) {
for (let c = 0; c < 9; c++) {
const v = grid[r][c];
if (!v) continue;
const key = `${r}-${c}-${v}`;
if (seen.has(key)) return false;
seen.add(key);
}
}
return true;
}
This step filters out invalid puzzles early and prevents unnecessary solver work later on.
Using logic to estimate difficulty
Difficulty is estimated using basic human style techniques rather than brute force.
The solver applies a small set of logical steps.
Naked singles
Hidden singles
Naked pairs
Each time a technique is applied, it is recorded. The hardest technique required becomes the difficulty indicator.
This approach is not perfect, but it is explainable and consistent, which mattered more to me than an opaque rating.
Counting solutions without freezing the page
Counting solutions requires backtracking, which can get expensive very quickly.
Running that on the main thread can lock up the browser, especially for open puzzles with few givens.
To avoid this, the uniqueness check runs inside a Web Worker with a strict time limit.
const worker = new Worker("worker.js");
worker.postMessage({ puzzle, maxSolutions: 2, timeLimitMs: 900 });
If more than one solution is found, the worker stops early.
If the time limit is reached, the result is reported as unknown instead of freezing the interface.
This keeps the page responsive even for difficult inputs.
Why keep everything static
Keeping the project browser only has a few practical advantages.
No server costs
No setup required
Easy to host on GitHub Pages
Simple to inspect or fork
It also makes sharing puzzles easier since the full state can live in the URL.
Demo and source
You can try the live version here:
https://sam-perry-usa.github.io/Sudoku-Analyser/
The full source code is available on GitHub:
https://github.com/Sam-Perry-usa/Sudoku-Analyser
Related
If you enjoy logic and number puzzles, you might also like Sudoku4Adults.


Top comments (0)