A Sudoku game built with Blazor Server on .NET 10, structured with Clean Architecture. Every puzzle is verified to have exactly one solution, and difficulty is graded by the solving techniques a puzzle actually requires - not just by how many clues were removed.
| Document | What it covers |
|---|---|
| Architecture | Layers, ports and adapters, dependency diagrams, project layout |
| Architecture review | SOLID / Clean Architecture findings, what was fixed, and what was deliberately left alone |
| Puzzle generation and difficulty | How boards are generated, why difficulty is technique-graded, performance numbers |
| Solving techniques | The human techniques the grader replays, with external references |
| Testing and CI | The unit test suite, the PowerShell smoke test, and the pipeline |
| Lessons learned | 38 real bugs grouped by kind, each with how it was found, the fix, and what now detects it |
| Security posture | What is checked in and what never is, CI permissions, and the rules for the Azure rollout |
| Deployment | Deploying to Azure App Service (Free F1) from GitHub Actions with OIDC and no stored secrets |
| Tech stack | Frameworks, tools and the reasoning behind each choice |
- Four difficulty levels - Easy, Medium, Hard, Professional, each graded by the techniques the puzzle genuinely demands (how that works)
- Unique solutions - every clue removal is verified to keep exactly one solution
- Reliable hints - answered from the solution recorded at generation time, so wrong entries can never break them
- Pencil marks (notes) - placing a real value sweeps that digit's notes from the row, column and box
- Undo / redo - full-board snapshots, so compound actions revert atomically
- Timer and best times - fastest solve per difficulty is remembered in the browser; auto-solve never sets records
- Mistake counter - judged against the known solution; undo does not forgive a mistake
- Game persistence - board, notes and the clock survive a page refresh, saved in encrypted browser storage with no database and no account (how it works)
- Real-time conflict highlighting, Validate / Solve / Clear All
- Keyboard-first grid - one tab stop; arrows move the selection, digits place values or notes, Backspace/Delete clears, N toggles Notes mode
- Screen-reader support -
grid/row/gridcellroles,aria-activedescendanttracking, descriptive per-cell labels
Prerequisites: the .NET 10 SDK
(version pinned in global.json).
dotnet run --project SudokuThen open https://localhost:7086 or http://localhost:5260.
dotnet test # 87 unit tests
./tools/smoke-test.ps1 -StartServer # 14 HTTP smoke checksThe build treats warnings as errors (see Directory.Build.props).
- Pick a difficulty to generate a new puzzle.
- Select a cell (click, or Tab to the board and use the arrow keys).
- Enter a digit with the keyboard or the number pad.
- Toggle Notes (or press N) to pencil in candidates instead.
- Use Hint for the selected cell, Validate to check for conflicts, Undo/Redo to step through your actions, and Solve to finish.
Dependencies point inward; the domain knows nothing about the outside world. Full detail, including the ports-and-adapters view, in docs/architecture.md.
graph LR
Host["Sudoku<br/>(Blazor Server host)"] --> Infra["Infrastructure<br/>(solver, generator, grader)"]
Host --> App["Application<br/>(use-cases, ports, models)"]
Infra --> App
App --> Domain["Domain<br/>(Board, Cell, Position)"]
Tests["Sudoku.Tests"] --> Infra
This project is open source under the MIT License.
- Leonhard Euler for Latin squares
- Howard Garns for inventing modern Sudoku
- Nikoli for popularizing it in Japan
