Skip to main content

Build a Sudoku Solver with a Visual UI

Level: Beginner · Time: 30–40 min · Category: Browser app

Tags: HTML · CSS · JavaScript · Prompting · Algorithms

Build a sudoku board in your browser with a New Puzzle button that generates a random puzzle and a Solve button that fills it in one box at a time, so you can watch the algorithm work.

There is nothing to install. No Python, no Node.js, no packages — the whole app is a single index.html file you open by double-clicking it. That makes it a good place to start, because the only new thing you are learning is how to work with an AI coding assistant.

It is also a good project for seeing what your assistant can do. The definition of done is precise, it is obvious on sight when something is broken, and the step-by-step animation means the model has to write real algorithmic code rather than something that merely looks plausible.

Prerequisites

That is the only setup required: no language runtime, no packages, no virtual environment.

Which assistant should I use for this one?

Any of them. OpenCode or OpenWork will create and edit index.html for you, which is the smoothest experience. VS Code with Chat works the same way. Even Open WebUI works here — it cannot write files, but this project is a single file, so you can copy its output into a text editor and save it yourself.

Pick a model with the Tools badge if you want the assistant to write the file directly, and ideally one with Reasoning — the backtracking solver is real algorithmic work.

What you will do

  • Set up a one-folder workspace and point your assistant at it.
  • Write one detailed prompt that specifies the whole app, including how "done" is measured.
  • Review the assistant's plan before any code is written.
  • Open the result in your browser and check it against a list.
  • Read the generated code and ask for a walkthrough of the part you do not understand.
  • Add two focused improvements, one at a time.

Build it step by step

1. Create the workspace

mkdir sudoku
cd sudoku

Then open OpenCode in that folder:

Open the OpenCode desktop app and point it at this project folder (sudoku).

Using OpenWork or VS Code instead? Open the sudoku folder in the app. Always open the folder, not a file — assistants read the folder for context.

2. Ask for the app

This is the whole project in one prompt. It is long, but every line removes a decision the model would otherwise have to guess at, which matters more with the models we host than it would with a frontier model. Paste it in as written.

CONTEXT
You are helping me build a browser sudoku app. I am a beginner. Everything must live in
one file, index.html, that I can open by double-clicking it. No build step, no npm,
no external libraries or CDN links.

GOAL
A 9x9 sudoku board with a button to generate a random puzzle and a button to solve it
one box at a time, visibly.

DONE MEANS
- I open index.html and see a 9x9 grid with clear 3x3 block borders.
- "New Puzzle" fills in a random solvable puzzle. Given numbers are bold and dark;
empty cells are blank.
- "Solve" fills the empty cells one at a time with a short delay so I can watch it,
in a different color from the given numbers.
- The solver is real backtracking, not a lookup table. Show me the backtracking:
when it undoes a wrong guess, briefly flash that cell red.
- A "Stop" button halts the animation mid-solve.
- A status line reads "Solved in N steps" when finished.

CONSTRAINTS
- Plain HTML, CSS, and JavaScript in one file. No frameworks.
- Comment the solver function so I can follow the algorithm.
- Under 300 lines.

PLEASE
1. Show me your plan in 4-6 bullets, then wait for me to say go.
2. Then write index.html.
3. Explain how to change the animation speed and the puzzle difficulty.

3. Read the plan before you say go

You asked for a plan first on purpose. Read it. A good plan mentions a backtracking solver, a generator that removes cells from a completed grid (rather than placing random numbers and hoping), and an animation driven by a timer so the browser can repaint between steps.

If the plan is missing something — say so now, before any code exists:

Your plan does not say how you will guarantee the generated puzzle is solvable.
Generate a complete valid grid first, then remove cells from it. Revise the plan.

Correcting a plan costs you a sentence; correcting finished code costs a rewrite. Of everything in this tutorial, this is the habit most worth keeping.

When the plan looks right:

go

4. Open it in your browser

The assistant writes index.html in your folder. Open it:

  • macOS: open index.html
  • Windows: start index.html
  • Linux: xdg-open index.html

Or just find the file and double-click it. Refresh the page after each change — there is no server to restart.

5. Check it against the list

Rather than glancing at it, work through the list you wrote in the prompt:

CheckWhat to look for
Grid9x9, with visibly thicker borders around each 3x3 block.
New PuzzleDifferent numbers each time you click. Givens are bold and dark.
SolveCells fill one at a time — not all at once.
ColorsSolved numbers are visually distinct from the given numbers.
BacktrackingCells occasionally flash red as it undoes a wrong guess.
StopHalts mid-solve and stays halted.
StatusShows a step count when it finishes.

Then the real test — is the solution correct? Pick any row, column, and 3x3 block and confirm each contains 1 through 9 exactly once.

Common first-attempt failures, and the prompt that fixes each

These are the particular ways this project tends to go wrong. Each one is fixed with a single focused follow-up rather than a rewrite.

Everything fills in instantly. The solver ran to completion before drawing. Ask:

The solve happens instantly instead of one cell at a time. The recursive solver is
finishing before the browser repaints. Record each step into an array as the solver runs,
then play that array back with setTimeout so I can watch it. Change nothing else.

The generated puzzle has no solution, or more than one. Ask:

Generate a complete valid grid first using the solver on an empty board with randomized
number order, then remove cells from that completed grid. That guarantees a solution
exists. Change nothing else.

It pulled in a library or a CDN link. Ask:

Remove the external script tag. This must be one self-contained file with no network
requests. Reimplement that functionality in plain JavaScript.

Stop does not stop. Ask:

The Stop button does not halt the animation. Keep the timer ID in a variable and call
clearTimeout on it when Stop is pressed, and set a flag the playback loop checks.

The page is blank. Open your browser's developer console (F12) and paste the red error text to the assistant with:

The page is blank. Here is the console error: <paste it>. Fix only this.

6. Understand the code you were handed

Before adding features, spend five minutes reading what you have. Reviewing is the part of this work where you add the most value.

If you set up the reviewer agent from the Voyager preset, run it:

@reviewer look at index.html

Then ask for the walkthrough that matters most:

Walk me through the solve function line by line, as if I have never seen recursion.
Explain specifically what happens when it hits a dead end and has to back up.
Do not change any code.

Read the answer alongside the actual code. It is a good way to learn backtracking: you have a working example, a visual of it running, and something that will answer follow-up questions.

How the solver works, in plain language

Backtracking is guess-and-undo. The solver finds the first empty cell, tries the number 1, and checks whether it conflicts with anything in that row, column, or 3x3 block. If it fits, the solver moves to the next empty cell and does the same thing again. If it does not fit, it tries 2, then 3, and so on.

If every number from 1 to 9 fails in a cell, that means an earlier guess was wrong. The solver erases the current cell, steps back to the previous one, and tries the next number there. That step back is the "backtrack" — and it is what your red flashing cells are showing you.

Because it never accepts a number that conflicts, and it never gives up until it has tried everything, it always finds a solution if one exists.

7. Add one improvement at a time

One feature per prompt, tested before the next. It is slower than asking for three at once, and it is how a working app stays working.

Difficulty selector:

Add a difficulty selector with Easy, Medium, and Hard that changes how many cells are
pre-filled when I click New Puzzle. Change nothing else.

Refresh and confirm all three difficulties produce visibly different boards — and that Hard is still solvable.

Conflict checker:

Add a "Check" button that highlights any cell conflicting with another in its row, column,
or 3x3 block. Do not change the solver.

Manual play:

Let me type a number into an empty cell by clicking it and pressing a key from 1 to 9.
Typing 0 or Backspace clears the cell. Given cells stay locked and cannot be edited.
The Solve button must still work from whatever state the board is in.

Refresh and test after each one. If a change breaks something that used to work, say exactly that:

That change broke the Stop button, which worked before. Fix only that, and do not
change anything else.

8. Make it yours

Pick one and see it through:

  • A timer, and a personal best time saved in localStorage.
  • A hint button that fills in one correct cell.
  • Keyboard navigation with the arrow keys.
  • A dark mode toggle.
  • An "undo" for your own moves.
  • Export the current board as text you can paste back in later.

More prompts to try

  • Ask for the worst case: "Give me a puzzle known to be hard for backtracking solvers, and show me the step count difference against an easy one."
  • Ask it to teach: "Add a 'Explain this step' mode that shows, in a side panel, why the solver chose each number."
  • Ask for a second algorithm: "Add a toggle to solve with constraint propagation instead of plain backtracking, and compare the step counts."
  • Ask for a review: "Review this file for anything that will confuse me in six months. Do not rewrite it — list the issues."
  • Ask about accessibility: "Make the grid usable with a screen reader and keyboard only. Explain each change."

Troubleshooting

  • Double-clicking the file opens a text editor, not a browser. Right-click the file → Open With → your browser.
  • Changes do not appear. Hard-refresh the page (Ctrl/Cmd+Shift+R). Also confirm the assistant saved to the same folder you opened.
  • The assistant keeps rewriting the whole file for a small change. Add "Do not rewrite the file. Show me only the lines that change." to your prompt, and put that rule in AGENTS.md.
  • The solver is correct but painfully slow to watch. Ask it to make the delay a variable at the top of the script, then tune it yourself.
  • Replies get worse the longer you work. Start a fresh session and tell it to read index.html first. Long sessions degrade — see why that happens.
  • The assistant cannot edit files at all. Your model probably lacks tool calling. Switch to a model with the Tools badge in the Voyager model list.

Next steps