
Sudoku — fun
Sudoku: why
Sudoku is such a simple and well known game. The strategies to solve the game can be mapped to software design patterns like:
- Publish/subscribe
- Event Sourcing
Then if you want to practice Agentic Coding then Game On! 🧐
Sudoku: ways to send a message
The three Sudoku projects aren’t really about solving Sudoku. They’re about message publishing between cells. Every cell belongs to one row, one column and one box, and it talks to the grid only through those three units. When a cell is assigned a digit, it publishes that fact to its row, column and box. Every other cell in those units hears the message and removes the digit from its own list of candidates. If that leaves a cell with a single candidate, or leaves a digit with only one possible cell in a unit, the game places that digit as well, which publishes new messages. One move can set off a whole cascade of these, and no central solver loop drives it.
All three projects share the same domain, the same REST API and the same Blazor front end. What changes is the protocol the cells use to send each other events (a cell was filled, a candidate was lost) and commands (place a move, place a deduction):
| Project | Transport | How the cells communicate |
|---|---|---|
| Sudoku-IObservable | IObservable<T> (Rx.NET) |
Each cell is an observable source, and its peers subscribe to it. Propagation is synchronous and deterministic. |
| Sudoku-DotNetChannels | System.Threading.Channels |
The 81 cells and 27 units are concurrent workers, each reading its own inbox. Messages are point-to-point, so a unit receives a cell’s event and passes it on to its other eight cells. |
| Sudoku-RabbitMQ | RabbitMQ streams | Each of the 27 units is a stream that its cells publish to and consume from: true publish/subscribe through a real broker. |
Going from Rx to channels to RabbitMQ, the same model moves from in-process reactive streams, to concurrent in-process messaging, to a distributed message broker.
Undo through event sourcing
Undo and redo are built on the well-known event sourcing pattern. The game never reverses eliminations in place. Instead, it records each accepted move in an append-only move history, which is the game’s event log. The grid is derived state: to undo, redo or jump to any point in the history, the game builds a fresh grid and replays the recorded moves up to that position. The cascades are recalculated, not stored, because the rules always produce them from the moves. This is also how a player gets out of a contradiction: step back to a move before it went wrong.
Agentic Coding
I wanted to try the grill-with-doc skill. If you never heard about that then visit Matt Pocock at https://www.aihero.dev/ All the skills md files in the repo’s below is the work of Matt - I didn’t modify them. So if you think those skills are wonderful, then I suggest that you go to Matt Pocock’s site.
The code can be found at:
- https://github.com/avantadore/Suduko-IObservable
- https://github.com/avantadore/Sudoku-DotNetChannels
- https://github.com/avantadore/Sudoku-RabbitMQ
Review the Grill-with-docs
This was my first experiment with grill-with-docs, so these thoughts are not really an expert’s view. But here’s what I think:
- The whole idea of getting to a point where all feature requirements are aligned before implementation works really well.
- The tasks produced by the grill-with-docs → to-spec → to-tickets workflow are incredibly detailed. I’ve never had specifications like these before AI.
- Everything is traceable.
- Maybe there’s too much documentation and too much to read. If you’re a little lazy or don’t have enough patience, you could end up just saying, “Yes, yes, yes, proceed.” 😃
What next
Replaceing RabbitMQ with Kafka - a little overengineered 😃