Source Code

<div class="db-app">
  <div class="db-header">
    <h2>Dots and Boxes</h2>
    <div class="stats">
      <div class="stat p1"><span class="stat-label">You</span><span class="stat-val" id="db-p1">0</span></div>
      <div class="stat p2"><span class="stat-label">CPU</span><span class="stat-val" id="db-p2">0</span></div>
    </div>
  </div>

  <p class="db-turn" id="db-turn">Your turn — click a dashed line to claim it.</p>

  <div class="db-board-wrap">
    <svg id="db-board" viewBox="0 0 320 320" xmlns="http://www.w3.org/2000/svg"></svg>
  </div>

  <div class="db-actions">
    <button class="ghost-btn" id="db-reset">New Game</button>
  </div>
</div>

Dots and Boxes Game — Free HTML CSS JS Snippet

Dots and Boxes Game · Games · Plain HTML, CSS & JS · Live preview

What's included

Features

Full Dots and Boxes rules on an SVG-rendered dot grid, not a static mockup
Separate horizontal and vertical edge arrays correctly model the line-based (not cell-based) game state
Completing a box grants an immediate extra turn, matching the real rule that drives all endgame strategy
A single move can complete two boxes at once when an interior edge is the last edge for both
Heuristic CPU opponent: claims any available box first, then avoids handing over a free third edge
Invisible wide hit-target lines layered over thin visible strokes for forgiving click/tap accuracy
Live per-player score tracking with a definitive win/tie message once the board fills
Configurable grid size via a single GRID constant

About this UI Snippet

Dots and Boxes Game — SVG Grid, Extra-Turn Rule & Heuristic CPU Opponent

Screenshot of the Dots and Boxes Game snippet rendered live

Dots and Boxes is a classic pencil-and-paper game played on a grid of dots: two players take turns drawing one line between two adjacent dots, and whoever draws the fourth and final edge of a 1x1 box claims it, marks it with their initial, and — critically — gets to go again. This snippet implements the full rule set on an SVG grid against a heuristic single-player CPU opponent, not just a static grid mockup.

Modeling a grid of lines, not a grid of cells

Most grid games track a 2D array of cell states. Dots and Boxes needs the opposite: the *lines between* dots are what players claim. This snippet uses two separate arrays, hLines[r][c] for horizontal edges and vLines[r][c] for vertical edges, sized so that a 4x4 dot grid (GRID = 4) produces exactly the right number of horizontal and vertical edge slots to bound a 3x3 grid of boxes. Each box's four bounding edges are looked up via boxLines(r, c), which returns the exact [type, row, col] coordinates of its top, bottom, left, and right edge in those two arrays.

Detecting a completed box

boxComplete(r, c) simply checks whether all four edges returned by boxLines(r, c) are already taken. After every line is claimed, claimLine() re-scans every still-unclaimed box on the board with this check — a line can complete more than one box at once, since an interior edge borders two boxes simultaneously.

The extra-turn rule that defines the whole strategy

The single rule that gives Dots and Boxes its distinctive endgame tension is this: completing one or more boxes grants the same player another turn immediately, rather than passing play. claimLine() tracks claimedAny across the scan and only switches current to the other player when the move claimed zero boxes. This is why skilled players deliberately avoid drawing a box's third edge — doing so hands the opponent a free box *and* an extra turn, chained potentially several boxes deep.

A CPU opponent that plays by that same logic

Rather than a random-move bot, cpuMove() follows a real two-tier heuristic: first, it checks every remaining line with wouldCompleteBox() and immediately claims any line that completes a box (chaining automatically, since claiming a box re-triggers cpuMove via the extra-turn rule). If no box can be completed, it filters candidates through createsThirdEdge() to avoid drawing a box's *third* edge, which would hand the human player a free box next turn — the same safe-move heuristic a beginner-to-intermediate human player uses.

Rendering with layered SVG

Boxes are drawn first (as filled, initially-transparent rectangles) so player-colored fills sit beneath the grid lines. Each unclaimed line is drawn twice — a thin visible <line> and an invisible wider db-line-hit line layered on top purely to make the actual click target far more forgiving than the 6px visible stroke, which matters a great deal on a dense dot grid.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how the horizontal and vertical edge arrays map to each box's four bounding edges via boxLines(), and why claimedAny — not a fixed turn counter — is what determines whether the turn passes to the other player. It's also a good candidate for extension — ask it to upgrade the CPU heuristic into a real minimax search over remaining moves (Dots and Boxes has a well-known "double-cross" endgame strategy worth implementing), add a chain-length indicator that highlights entire connected regions of 2-edge boxes, or convert the single-CPU setup into local two-human-player mode.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a two-player Dots and Boxes game in plain HTML, CSS, and JavaScript, rendered on an inline SVG grid — no libraries, one human player versus a CPU opponent.

Requirements:
- Model a grid of dots (e.g. 4x4, producing a 3x3 grid of boxes) using two separate data structures: one for horizontal line state between horizontally-adjacent dots, and one for vertical line state between vertically-adjacent dots. Do not model the game state as a grid of cells only — the lines between dots are what players actually claim.
- Render every dot, every unclaimed line as a clickable target, and every claimed line in the color of whichever player claimed it, with each box in the grid filled with a light tint and an initial once completed.
- Detect when a move completes a box: a box counts as complete only once all four of its bounding edges (top, bottom, left, right, correctly looked up from the two line arrays) are claimed. A single move can complete two boxes at once if it is an interior edge shared by two boxes.
- Implement the real Dots and Boxes turn rule: if a move completes one or more boxes, the same player moves again immediately instead of the turn passing to the other player; the turn only passes after a move that completes zero boxes.
- Track a running score per player (number of boxes claimed) displayed live, and end the game with a clear win/tie message once every box on the board has been claimed.
- Implement a CPU opponent using a two-tier heuristic: first check every remaining line for one that would immediately complete a box and play it (chaining automatically via the extra-turn rule); if none exists, avoid playing any line that would bring a box up to exactly three claimed edges (since that would hand the human a free box), and otherwise pick randomly among the safe remaining lines.
- Make each thin visible line have a much larger invisible click/tap hit target layered on top of it, so clicking near a line (not just exactly on its few-pixel-wide stroke) still registers.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Click a dashed lineClick any unclaimed edge between two dots to draw it in your color (indigo).
  2. 2
    Complete a box for an extra turnDrawing a box's fourth edge claims it and marked with "Y" — and grants you another turn immediately.
  3. 3
    Watch the CPU respondThe CPU (red, marked "C") claims any box it can immediately, and otherwise avoids drawing a box's third edge to deny you a free capture.
  4. 4
    Track the scoreClaimed boxes tally live in the header for both players; the game ends once every box on the board is claimed.
  5. 5
    Change the grid sizeEdit the GRID constant in the JS panel — GRID = 4 produces a 3x3 box grid; GRID = 5 produces a larger 4x4 box grid.
  6. 6
    Start a new gameClick "New Game" to clear every line and box and return to your turn.

Real-world uses

Common Use Cases

Classic pencil-and-paper game collections
A faithful digital version of a game usually played on graph paper, alongside other turn-based games such as the Tic-Tac-Toe Game or Connect Four Game.
Teaching edge-based (not cell-based) grid modeling
A clear example of a game where the graph structure being claimed is the lines between cells rather than the cells themselves — a useful pattern beyond just this one game.
Reference for simple heuristic game AI
The two-tier "take a free box, else avoid giving one away" heuristic in cpuMove() is a readable, non-trivial starting point for building smarter single-player opponents in other grid games.
Kids and casual game sections
A simple, low-stakes, quick-round game well suited to a family or casual games hub alongside other short two-player games.
SVG hit-target pattern reference
The paired thin-visible-line plus wide-invisible-hit-line technique is directly reusable anywhere a thin SVG stroke needs a much larger click/tap target.

Got questions?

Frequently Asked Questions

This is the actual rule of Dots and Boxes, not a simplification: whenever a move completes one or more boxes, the same player immediately moves again instead of passing play. claimLine() tracks whether the move claimed any box (claimedAny) and only switches current to the other player when it did not.

cpuMove() first checks every remaining line for one that would immediately complete a box (wouldCompleteBox) and plays it if found — chaining automatically through the extra-turn rule. If no box can be completed, it filters out any line that would create a box with exactly 3 edges taken (createsThirdEdge), since that would hand the human player a free capture, and picks randomly among the remaining safe lines.

Yes. claimLine() re-scans every unclaimed box on the board after each line is drawn, not just the boxes touching that specific line in an obvious way — an interior edge borders two boxes at once, so completing both simultaneously is correctly detected and both are awarded.

Two separate boolean-ish arrays track claimed state: hLines[r][c] for horizontal edges and vLines[r][c] for vertical edges, sized so a GRID x GRID dot grid produces the right number of each. boxLines(r, c) maps a box's row/column to the exact four edge coordinates in these two arrays.

Edit the GRID constant in the JS panel. GRID counts dots per side, so GRID = 4 (the default) produces a 3x3 grid of boxes; GRID = 5 produces a 4x4 grid of boxes, and so on.

Yes — replace the setTimeout(cpuMove, 550) call in claimLine() with nothing, and change the hit-line click handler to call claimLine(type, r, c, current) instead of hardcoding 'p1', so whichever player's turn it is claims the line they click.