A PyTorch policy network, cloned then trained by playing
A small convolutional network copies a two-move search, then improves through 16,384 games. It finished about 40% short of its teacher.
rejectedrecordedLearn what makes a Drop7 board good from small cell patterns and millions of self-play games.
12 approaches, featured pages first. The label above each title is the technique the approach uses; the same pages appear under that technique on the approaches index.
These play no game of their own: engines run the games and diagnostics measure them. They are listed here because they live alongside the approaches above; the full sets are under Engines and Diagnostics.
The C++ program trains the original n-tuple evaluator, searches with it, benchmarks the fast engine, and runs the shared self-tests.
Instead of hand-writing what makes a Drop7 board good, learn it — from small patches of cells, and from millions of games the program plays against itself.
This is the family that tried to replace human judgement with data. It contains the repository's first learned policy and, after it, a long line of reinforcement-learning variants: temporal-difference updates, Q-learning, policy gradients, actor-critic, and expert iteration. Through August 2026 none of them produced a policy stronger than the hand-tuned fair depth-4 search that the project uses as its reference. On 2026-09-05 the row-and-column lookup tables, trained from billions of engine moves and placed as the leaf of the depth-3 fair search, beat that reference on 256 held-out games at screen tier, and on 2026-09-06 the same frozen tables did it again on 512 games from a second block nothing had read; a six-times-wider evaluator trained until its validation margin stopped rising passed the same gate and was no better than the first. Later that day the same tables played one ply deeper, as the leaf of the depth-4 search, and gained about as much from the fourth ply as the hand-written leaf does, keeping their whole margin over it. For how this family compares with the other three ways of learning tried here, see four ways a program can learn Drop7.
Pick a small window of cells — four in a row, four in a column, or a 2×2 block. Read the contents of that window as an address, and look the address up in a table of learned numbers. Do that for every window on the board, add all the numbers together, and the sum is the network's opinion of the position.
The position in the figure is this repository's TypeScript rules engine playing
a game, not a drawing. The native implementation in
src/core/native/ntuple.hpp uses 92 windows — 28 horizontal, 28 vertical, and
36 square — sharing 17 underlying tables.
Nothing in that machinery knows Drop7's rules. It only knows which small patterns of cells tended to precede good games. That is the appeal: a table lookup is far cheaper than a neural network, and the tables can hold millions of distinct local shapes. In 2048, the game this idea was borrowed from, tables like these are enough to play the game very well.
No human labels the boards. The program plays a game, sees what happened, and nudges the weights it looked up toward the outcome. Play enough games and the weights are supposed to converge on something that ranks positions correctly. The variants in this family differ mostly in what they nudge toward: the score that followed, the number of moves survived, the value of the best next move, or the advantage of one column over another.
The first version worked well enough to be interesting and was never beaten by anything that came after it. Adding a two-move look-ahead on top of the learned values lifted it from about 182,000 to about 232,000 points per game on a fixed 64-game development probe. The improvement was real and measured on paired games. But by the time the hand-tuned depth-4 search was properly measured, that search was scoring around 308,000 on its own 64-game reference cohort, and the learned policies were not close.
Every reinforcement-learning variant that followed landed lower. The clearest example: a phase-aware n-tuple trained on 50 million moves scored 181,733 points per game, and the two-rise-deep search built on top of it scored less, at 113,644. A Rainbow-style Q-learner beat random play convincingly at 250,000 training steps, then lost decisively to a plain one-move fair search at one million. A PyTorch policy-gradient pipeline, an actor-critic with explicit safety constraints, and eight rounds of expert iteration all finished between roughly 116,000 and 176,000 points per game, and a second, C++ policy-gradient attempt never got past trying to imitate a one-move search.
| Approach | Recorded mean score | Mean moves | Cohort | Source |
|---|---|---|---|---|
| Row and column lookup tables as the depth-4 leaf, the same frozen tables one ply deeper | 516,155 | 148.75 | 512 never-read paired development games on a fourth block, screen tier | RS-20260906T171746Z-1623f833 |
| Row and column lookup tables as the depth-3 leaf | 484,577 | 140.21 | 256 never-read paired development games, screen tier | RS-20260905T215332Z-95d18a5a |
| Row and column lookup tables as the depth-3 leaf, replication of the same frozen tables | 487,066 | 140.83 | 512 never-read paired development games on a second block, screen tier | RS-20260906T040113Z-6ba93171 |
| Wider lookup tables (2x4 and 4x2 windows added) as the depth-3 leaf | 481,869 | 139.39 | the same 512 games, screen tier | RS-20260906T040113Z-6ba93171 |
| Learned value plus depth-2 search | 232,107.156 | 70.766 | 64-game development probe | ledger |
| Optimistic phase n-tuple, direct play | 181,733.422 | 56.359 | 64-game burned gate | ledger |
| Primal-dual actor-critic | 175,834 | 55.006 | 512-game calibration | ledger |
| PyTorch PPO, best candidate | 142,677.781 | 45.656 | 64-game development cohort | ledger |
| Regenerative expert iteration, round 8 | 116,598 | 38.046 | training roll-ins | ledger |
| Optimistic phase n-tuple, two-rise search | 113,643.969 | 37.375 | 64-game burned gate | ledger |
| Fair depth-4 reference, for comparison | 308,295.578 | 90.031 | 64 games | ledger |
Every figure above is ledger-recorded in
the experiment history; the family's status rows are
in the experiment index under "N-tuple and
reinforcement learning". Five of the family's sources
(bellman-ntuple.cpp, flow-curriculum-rainbow.cpp,
manifold-gail-development.cpp, manifold-gail-scaled.cpp,
curriculum-option-ppo.cpp) carry a task-record only verdict: an index row
exists, but no ledger protocol, artifact hash, or per-game data was retained,
so those rejections cannot be re-derived.
The 308,295.578 / 90.031 reference is itself weaker evidence than it looks. It
appears once in the ledger, as an internal bootstrap comparator inside the
regenerative expert-iteration run; the identity of its 64 seeds, its dispersion,
and its censoring statistics were not retained. This is recorded as finding H2
in docs/exploratory/audit-03-claim-arithmetic.md.
The scoring-mode assignments quoted on the individual pages come from the same audit, which classifies every recorded (score, moves, n) triple in the ledger by which level bonus is arithmetically consistent with it. Where the ledger states the mode, the pages say so; where the audit infers it, the pages say that too.
No approach in this family opened a protected or final cohort. Several left their later gameplay ranges unopened, which is recorded per experiment.
The representation was never the bottleneck. The strongest single lesson is negative and repeated: more capacity, more training, and better-conditioned updates did not fix these policies. A shared-parameter bug in the temporal-difference update was found and corrected, and the corrected policy still failed. Conditioning the tables on the rise clock closed under 3% of the gap to the reference search. Training a Q-function to 50 million moves produced a policy no better than one trained far less.
The bottleneck was which moves the data covered. Almost every program here learned from the move it actually played, then, at play time, was asked to rank up to seven columns it had never been scored on. That is the sibling trap. The expert-iteration run showed that even regenerating fresh on-policy games every round did not remove it, because the targets still described only the played action.
Search on top of a weak value can hurt. The two-rise rollout over the optimistic phase n-tuple was strictly worse than just playing the network's first choice. A deeper look-ahead magnifies whatever the leaf evaluator gets wrong, and this one was wrong.
What is still open. Nobody has trained an n-tuple on data that scores every legal column at each position under shared imagined futures. The sibling-ranking and scale-out pages describe what that would take. Until it is tried, this family's negative results rule out the objectives that were tested, not pattern learning itself.