DEV Community

Cover image for I built a sudoku app where the AI coach is never allowed to be wrong
Raz Chiriac
Raz Chiriac

Posted on

I built a sudoku app where the AI coach is never allowed to be wrong

I play sudoku most mornings. Every app I tried was either slow to enter digits, covered in ads, or both. So I built Kodiak Sudoku, and along the way I ran into three problems that turned out more interesting than I expected.

1. Making 81 cells feel instant

A sudoku board is 81 cells, each with up to 9 pencil marks. If typing a digit rerenders the whole grid, you feel it, especially on a cheap phone.

What worked:

  • Zustand with one selector per field. Each cell subscribes only to its own value, its notes and whether it's selected. Typing a 7 rerenders one cell, plus the cells that need to highlight matching 7s.
  • Notes as bitmasks. All 81 cells' notes live in a single Uint16Array. Bit 3 set means "3 is a candidate". Toggling a note is one XOR, and comparing two cells' notes is one integer compare, which makes the memoized cell comparator trivial.
  • Keyboard first. Arrow keys or hjkl to move, digits to place, N for notes mode, U and R for undo and redo, ? for the full list. One window-level listener reads from the store directly, so there's no React state in the hot path.
// toggle candidate d (1-9) in cell i
notes[i] ^= 1 << d;

// is d a candidate?
const has = (notes[i] & (1 << d)) !== 0;
Enter fullscreen mode Exit fullscreen mode

2. A daily puzzle you can't cheat

The daily puzzle has a leaderboard, and a leaderboard is only worth anything if it's honest. The rule I set early: the solution never reaches the browser.

  • The client gets the givens only.
  • Hints go through a server action that looks up the stored solution, returns one cell, and records that you used a hint.
  • When you finish, the server compares your board with the stored solution before writing a completion.
  • Anonymous solves don't count toward the board. You can play without signing in, but the leaderboard needs an account.

Hints are allowed on the daily, and the board shows how many each player used. That turned out fairer than banning them. There are now weekly, monthly and all-time standings too, ranked by dailies solved and then average time.

3. An AI coach that can't hallucinate a move

This was the part I was most nervous about. I wanted a coach that looks at your actual board and says something like "look at box 5, the 4 can only go in two cells". Language models are good at that kind of explanation. They are also very good at confidently suggesting a digit that's wrong.

A wrong digit on someone's board is the worst possible failure. It's silent, and it breaks trust in everything else. So the design is:

  1. The model sees the board, never the solution. It has to reason about the position like a person would.
  2. The output is a strict schema. A short nudge, a one-sentence reason, and an optional move (cell plus digit). Anything that doesn't parse is thrown away.
  3. Every suggested move is checked server-side against the stored solution and against the deterministic solver's next step. If it fails, the move is dropped and only the explanation is shown.
  4. There's a 2.5 second budget. If the model is slower, the player gets a deterministic hint from the solver with a canned explanation for that technique. The panel never comes back empty.
  5. The client can't redirect the check. Each request verifies that the submitted board's givens match the original puzzle, so a tampered board can't point the validator at a different solution.

The validation function is the most heavily tested code in the project. Rejected moves are logged, so I can see if a model update starts guessing more.

Teaching, not just solving

The coach works best when the player knows the vocabulary, so I added a Technique Journey: 15 short lessons from naked singles to swordfish. Each lesson is a real, verified puzzle you solve in place, and the same boards show up inside the blog posts, so you can try an x-wing right next to the explanation.

Stack

Next.js 15 (App Router), React 19, Supabase for Postgres and auth, Drizzle with hand-written SQL migrations, Zustand, Zod at every server boundary. Hosted on Vercel. Payments are Stripe Checkout called with plain fetch, no SDK. Puzzles come from a public dataset of 3 million rated sudokus, bucketed into four difficulty levels, and every one is checked by the solver for a unique solution.

How it pays for itself

The game, the daily, the leaderboards and the lessons are free with no ads. Kodiak Plus adds the AI coach, AI post-game debriefs and unlimited quick play. Everyone else still gets solver-based hints. There's also an Android app.

If you play, I'd love to hear how the keyboard controls feel and whether Hard is actually hard. The daily puzzle resets at midnight UTC.

Top comments (0)