What it does
For each slot machine, it predicts the chance that the next spin pays 0x, 1x, 2x, 5x or 20x. The predictor is plain Python standard library and deterministic, and a fresh unzip of our code ZIP recreates the submitted CSV byte for byte.
How we built it
We read the simulator's behavior out of the data one rule at a time, and kept a rule only when it held across machines.
- Win chance follows a lag pair. Whether the spins at two fixed lags both won or both lost ("match" vs "differ") sets a high or low win rate. Each machine uses one of three pairs. We infer which one from its own history with a Bayesian likelihood, and shrink the cell rates toward the group.
- Payout size has two exact states. Whether the spin at the pair's first lag paid big sets the 1x share, with a per-machine sign. The two values per machine type, and the 2x/5x/20x split, are the same to 1e-15 across every machine.
- Changes. A changepoint mixture covers stable machines, machines that change on their own, and machines that change together across an episode. After a change the rule mirrors, since every changed machine fully reversed.
- Small shifts. The win odds move a little with the size state, the machine's signal, and other machines' recent wins.
- Short histories. When the tick that sets the size state is missing, we average over both possibilities instead of guessing.
- Round two in ten minutes. derive.py re-reads every structural constant from a new kit. When round two dropped, it found the new lag pairs (1,4), (2,6), (3,8) and the new neighbor lag on its own, and a watcher built, checked and packaged the entry about 10 minutes after the kit appeared.
Results (public validation, kit scorer)
- Main round: R = 0.022, where the pooled starter is R = 1.
- Round two: 19.58 of 20 points (R = 0.021). Main-round settings applied to the new kit scored only 10.3, so re-deriving the rules is what mattered.
Challenges we ran into
Validation is small, so random noise is about as big as most ideas. Every change had to beat the current model on both halves of validation and on rewind backtests that replay each machine's own history, where the Brier gap is an unbiased estimate of the true error gap. That rule rejected several ideas that looked good on validation alone.
What we learned
Structure beats tuning. Almost all of the score came from finding the right rules, and almost none from tuning settings. Heavy sweeps ran on Snowflake so our laptops stayed free.
Built With
- claude-code
- python
- snowflake