In previous episode we built 0n0FF, a minimalist tile flipping puzzle game in React
and TypeScript
. This time we’re giving our game a brain.
We are adding a solver that can compute the optimal solution to any board state and then show the next best move directly to the player using a subtle, gray toned guide beneath the main board.
What You’ll Learn
- How to solve a logic puzzle with breadth first search (BFS)
- How to represent board states as bitmasks for performance
- How to integrate a solver into an interactive React UI
- How to visualize solver hints without distracting from gameplay
- Why immutability and clean state separation matter
Project Code
You’ll find the complete source code here: 0n0ff-puzzle
How It Works
The core idea is simple: treat each board state as a node in a graph. A move transforms one state into another and we search for the shortest path to the win condition (all green tiles).
To avoid visiting the same state twice we encode the board as a single integer (a bitmask of 16 bits for a 4x4 grid). This turns a potentially slow puzzle solver into a blazing fast pathfinder.
;
Breadth First Search (BFS)
Using a BFS loop we explore all possible move sequences from the current board state, stopping the moment we find a winning path.
while queue.length
Each move toggles an entire row and column which we simulate using XOR on the bitmask.
Solver Integration
Once the solver is in place, we run it:
- At the start of each new game
- After every player move
This allows us to continuously maintain an up to date optimal path to the win state. The next move is then shown to the player (but only subtly).
Visualizing the Hint
Beneath the main board we render a semi transparent, grayscale copy of the grid with a darker highlight on the next suggested move:
And in CSS:
}
Pure State, Clean React
To keep things clean and reactive:
- We track both the initial and current board state
- The solver output is stored in
state.solver
- We added a “Reset Game” button to return to the initial configuration
This ensures the solver always computes from the true current board and allows for easy restarts or comparisons.
Performance
Thanks to bit manipulation and BFS:
- Solving from any state is instant
- We support perfect solutions on every move
- No async, no lag, no external dependencies
Final Touches
We updated the header to show:
- The number of remaining moves in the current optimal path
- The original minimum solution length (for comparison)
This adds a layer of motivation for players trying to solve it on their own.
Future Ideas
- Animate the full solution path step by step
- Let players request a hint only when needed
- Track player vs solver efficiency
- Add different grid sizes or random move obfuscation