
Building a Sliding Puzzle with Vanilla Canvas and AI: Classic 15-Puzzle
The 15-puzzle — a 4x4 grid of numbered tiles with one empty slot — has been a staple of logic puzzles since the 1870s. This week I built a playable version using nothing but the HTML5 Canvas API, with help from DeepSeek V4 Flash. No framework, no physics engine, just raw canvas rendering and a BFS-based AI solver.
Play the Game
Slide tiles to arrange the numbers 1–15 in order. Beat your best time and move count.
Built by DeepSeek V4 Flash — 4×4 sliding puzzle with BFS bot solver, keyboard support, and move counterClick a tile adjacent to the empty slot to slide it · Use arrow keys to slide tiles into the gap · Press R to shuffle · Try Bot mode to watch the AI solve the puzzle in optimal moves.
Why Vanilla Canvas + Puzzle
The 15-puzzle doesn’t need a game engine. There’s no physics, no sprites, no collision detection — just state management, rendering, and input handling. The HTML5 Canvas API is the leanest possible choice:
- Zero dependencies — no CDN loads, no framework overhead. A single
<canvas>element and a few hundred lines of JavaScript - Full control — every pixel is yours to command. Tile rendering, rounded corners, solved-state overlay — all done with raw canvas draws
- Instant load — the page weighs under 10KB. On a 4G connection, it’s playable before you finish reading this sentence
- Mobile-friendly — CSS
max-width: 100%on the canvas handles responsive scaling without any engine configuration
For a puzzle game that’s pure UI logic, a full engine like Phaser or PixiJS would add hundreds of kilobytes of unnecessary abstraction.
The Build
The game logic is the classic 15-puzzle: 16 positions in a 4x4 grid, 15 numbered tiles, one empty slot. Click a tile next to the empty space and it slides in. The puzzle is solved when tiles are in order 1–15 with the empty at bottom-right.
What DeepSeek V4 Flash got right:
- Solvability check — not every random shuffle produces a solvable puzzle. The AI correctly implemented the inversion-count parity check: for even grid sizes, solvability depends on how the parity of inversions relates to the empty row’s distance from the bottom. Shuffles are re-rolled until both solvable and not already solved.
- BFS bot solver — the bot mode uses breadth-first search on the game state space, finding the optimal (shortest) solution path. Each state is packed into a BigInt hash for fast visited-set lookup. On a 4x4 puzzle, BFS finds the solution in milliseconds.
- Keyboard support — arrow keys slide tiles into the gap, mapped inversely (pressing Down slides the tile above the gap down, etc.). This is the correct mapping for tactile play.
- Tile rendering — each tile gets a unique color from a palette of 16, with rounded corners via
roundRectand centered number text. The empty slot renders transparently. - Timer and move counter — both update in real-time, and on solve the timer freezes with a “Solved! Xs” message.
What needed fixing:
- Single-line output from Flash — the initial game HTML came as one long minified line. This is a known Flash quirk — the code is correct, but the formatting makes it hard to review and edit.
roundRectpolyfill —CanvasRenderingContext2D.roundRect()isn’t available in all browsers. The AI included a polyfill that falls back to quadratic curves, keeping tile corners rounded across all modern browsers.- No shuffle animation — the AI didn’t add a shuffle animation. Tiles snap instantly to their new positions. This is intentional for the game’s minimal design but might be a polish area for future versions.
Lessons Learned
Vanilla Canvas is ideal for pure state-based games. The 15-puzzle has exactly one mechanic (slide a tile), and the rendering is deterministic — given the same state, the canvas output is identical every frame. There’s no physics tick, no frame interpolation, no animation loop complexity. This means:
- Zero game-loop bugs — no Phaser scene lifecycle, no Three.js rAF pipeline, no PixiJS ticker tuning
- Direct input handling — one
clickevent listener computes tile position from mouse coordinates. No scene-to-world coordinate transforms needed - Minimal debugging — when something breaks, it’s almost certainly in your state logic, not in engine configuration
What you’d miss from a framework: animation easing (for smooth tile sliding you’d write it yourself), mobile gesture handling (no built-in swipe detection), and device-pixel-ratio handling (you get blurry canvas on Retina without manual resolution management).
Cost & Stats
This game was produced by DeepSeek V4 Flash in a single generation:
- Input tokens: ~2,500
- Output tokens: ~2,800
- Cost: ~$0.0008
- Build time on first generation: 68 seconds
- File size: 9.9KB (standalone HTML with all CSS, JS, and bot mode)
Try it Yourself
Play the Sliding Puzzle on aigamingdev.com. Try to solve it in under 30 moves — the BFS bot typically solves in 45–65 moves depending on the shuffle. There’s also a bot mode that solves the puzzle in real-time using BFS.
The source is on GitHub if you want to adapt the puzzle logic for your own projects. Swap the 4x4 grid to 3x3 for an easier variant, or add smooth slide animations and a move-history replay feature.