/building · 2026
Drop7 Solver
game theory · expectimax · iterative deepening
My first public GitHub project was a Java simulation of the iPhone game Drop7, so I could pick the statistically optimal move. I rebuilt it as a playable TypeScript game with a more advanced solver that runs in your browser.
Drop7 was an iPhone game played on a 7x7 board where you drop numbered discs. A disc explodes when the contiguous occupied segment containing it in either its row or its column has the same length as the number on the disc. You lose if the board fills up with discs.
When a disc explodes, it can change the segment lengths for other discs, which can set off some very enjoyable chain explosions. This is also the key to achieving a high score: a disc cleared in chain wave d earns floor(7 × d<sup>2.5</sup>) points, so later waves are worth much more without being exponential.
There are also "hidden discs" which need to be revealed by exploding other discs around them. Every fifth move pushes up a new hidden row, and a disc in a hidden row is revealed after two adjacent explosions.
The game mechanics seem complicated, but once you start playing it is very intuitive.
play
you choose every column
score0
level1
row in5
What a strong board looks like#
The useful strategy writing I could find converges on a long-horizon idea. Adam Saltsman describes keeping covered discs high and preserving a “fertile” topology that can keep exposing new numbers. Another detailed player guide emphasizes delayed chain patterns and the danger of low-number clogs such as adjacent 1s or long runs of 2s. In other words, the best-looking move often scores nothing now: it stores a trigger that can release several discs after a future drop or row rise.
David Walton's Sequence-mode solver scored 5,205,955 by searching windows of 14 known discs, committing only the quiet setup before the best chain trigger, and replanning at that trigger. That event-boundary idea is useful, but the result is not comparable to this game: his solver knew hundreds of future discs and the values hidden in incoming rows, and used roughly 465 trillion simulated drops. I also found an earlier Q-learning experiment, but no public-state Hardcore solver that demonstrated sustained high-level play. Work on n-tuple value functions for 2048 and Stockfish's NNUE evaluator is more transferable architecturally: represent local board patterns with a compact evaluator that is cheap enough to call at every search leaf. None of those references supplies a Drop7 evaluation function, so every proposed feature still has to win complete seeded games here.
Search the decisions and the chance#
The new evaluator alternates between two kinds of node: a decision over every legal column, then a chance node over the seven possible next discs and every number that could be hiding under a newly opened gray. It searches one move deep, then two, then three, keeping the last depth it finished before the time budget expired. The positional estimate at the unfinished horizon values open columns, gravity-reachable chain setups, and covered discs exposed to a future explosion. It penalizes tall stacks and low numbers that have already overshot the line length they need.
evaluate
search recommends; you decide
score0
level1
row in5
The utility under each column is not a promise of points. It combines exact score outcomes inside the search horizon with a survival estimate at its edge. What matters is the comparison between columns on the same board.
The distinction between a setup and a clog is important. My first horizon score used the absolute difference between a disc and its row or column length. That made a 3 in a two-disc line look promising, but it also rewarded two adjacent 1s and three adjacent 2s. Those lines are one away in the wrong direction. The current model only gives direct potential to lines that can grow into a match. It gives delayed potential to discs that can be released by one of those buildable triggers, and separately penalizes adjacent ones, runs of three twos, and low discs that are overshot on both axes. That clog penalty fades when a reachable perpendicular trigger can break the run; three bottom-row twos can be useful chain fuel rather than dead weight.
There is also a useful conservation check. Every move adds one numbered disc, and every five moves add a seven-disc covered row, so an indefinitely stable board must approach 1 + 7/5 = 2.4 numbered clears per move. Reveals do not reduce occupancy, but they determine how much covered material becomes usable chain fuel. In one development replay, the same public depth-four policy built quietly at 1.44 clears and 0.80 reveals per move for its first 25 moves, released at 2.68/1.72 over the next 25, and eventually scored 1,246,684 points. A paired early failure managed only 1.92/1.16 in that release window and clogged after 55 moves. One long game is not a benchmark result, but it turns “potential energy” into a testable question: can a policy enter that flow regime often, and can it stay there?
That is still a theory, not a proof. A headless tournament runner plays complete seeded games with the old heuristic, the potential-only and anti-clog ablations, and the combined model. Every policy gets the same future-disc sequence; a deterministic work budget avoids comparing one heuristic at a deeper completed search than another. The report includes means, medians, percentiles, paired deltas, win/loss counts, incomplete searches, and censored games.
npm run drop7:bench -- --profiles legacy,potential,anti-clog,combined --games 64 --depth 1 --max-work 200000 --max-moves 500
For testing browser performance instead of heuristic quality, --time-limit-s 1 replaces the deterministic work budget with the same wall-clock limit used by the interactive solver.
auto
search chooses and plays
score0
level1
row in5
The original solver#
The code I wrote in 2010 captured the core drop, gravity, and explosion rules, but the rules, randomness, scoring, and search were all mixed together. Its rollout did not include the five-move row rise, its caller mixed zero- and one-based column numbers, and the normal-play path cracked gray discs without replacing a fully revealed gray with a random number. The rebuilt engine treats a move as a pure state transition. Explosions in the same wave happen simultaneously, gravity waits until the wave is over, and every random reveal can be replayed exactly in a test.
The original program averaged randomly generated future discs and most importantly, random future column choices after the opening choice. That is, there was no pruning of moves that were clearly suboptimal, so it simply measured how an opening move fared under random subsequent play (not how it fared if every later move was also chosen well).
The original solver was intended to inspect roughly 79 possible combinations of the opening column plus four future discs and columns. The checked-in version never completed that enumeration: it omitted the final permutation and its zero/one-based column mismatch throws on the first column. There is therefore no trustworthy numerical 2010 baseline to compare with the complete-game results above.


The horizon effect on the original solver meant that it would not stack up discs into complex chain reactions.
This was a precursor to my future involvement in chess engine development.
links