Inspiration
House Edge asks for something deceptively simple: given a slot machine's past spins, output the probability of each payout (0×, 1×, 2×, 5×, 20×) on the next spin. Each machine follows hidden rules: payouts interact at lags of up to 8 ticks, machines of the same type can react in opposite directions, patterns drift or change across a whole episode, and some machines only show a sparse slice of their history. We liked that it rewards calibrated probabilities, not lucky guesses: every forecast is compared with the simulator's true odds.
What it does
For every queried machine, our model reads that machine's spin history (and its neighbors' earlier spins) and outputs five calibrated probabilities for the next spin. When the simulator's patterns change in the adaptation round, the same pipeline retrains on the new data within the time window.
How we built it
1. Baselines and a sequence model. The pooled starter scored 30/60. Gradient boosting with 264 hand-built lag features reached only ~34. A per-machine causal LSTM reads the payout history tick by tick (last 4 payouts per step, plus machine type and signal); its prediction at tick $t$ uses only payouts at ticks $< t$, and missing ticks stay "unknown", never zero. An MLP head that also sees the last 8 payouts directly brought one model to ~50, and a 5-model ensemble to 53.20.
2. The big unlock: next-spin training on every released history. Every tick in a history before a query's cutoff is itself a valid next-spin example. So besides the training split, we trained on the validation and test histories (ticks strictly before each cutoff, never the cutoff spin, true probabilities or condition labels). That gave about 4× the training targets (121k → 488k) and lifted one model from 50.47 to 55.50, with errors roughly halving in every condition.
3. Short-history augmentation. Short-history machines show the 40 most recent ticks plus 24 randomly sampled older ones. We generated extra training views from long histories with exactly that pattern (and a "recent ticks only" variant), so the model practises predicting from sparse context.
4. Variants and a tuning-only blend. We trained several variants: an exponential moving average of the weights (better calibration), a permutation-invariant summary of the other 7 machines in the episode, extra augmented views, and a 2-layer LSTM. A forward-selection blend, with weights and one temperature $T$ fitted only on half of validation, combines them. Main round: 57.15/60 (tuning 57.05, untouched audit half 57.27).
5. Adaptation round. Our main ensemble scored only 9.11/20 on the new validation set, worse than the starter. A quick mutual-information check showed why: in main data the payout 7 ticks back was the strongest signal; in the new data that effect had vanished and lag 3 had appeared. Retraining the same recipe from scratch on the new data (fine-tuning from the main checkpoints did worse) got a single model to 18.97/20 and a 4-model blend to 19.05/20.
Challenges we ran into
- Overfitting a tiny validation set. Each half of validation has only 12 episodes per condition, so differences under ~0.2 points are noise. We fitted everything on a tuning half and kept an audit half as a check; several ideas that looked good on tuning (length-gated blends, per-machine-type temperatures) fell apart on audit and were dropped.
- Staying strictly causal. Using validation/test histories is only valid if no target at or after a cutoff ever enters training. We wrote explicit checks (zero targets at or after any cutoff) and kept neighbor features to ticks $< t$.
- Misleading diagnostics. Jackpot machines looked about 2× worse, but that came from normalizing by a baseline that happens to do well on them. In absolute error they matched the other types, and the score normalizes per condition, not per type.
- Reproducibility. Organizers rerun our code on Linux with a $10^{-8}$ tolerance. Inference runs in float64 with deterministic CPU ops, and we verified that a read-only unpacked copy reproduces our CSV to within $4\times10^{-16}$.
- Distribution shift under time pressure. The adaptation window was short, so we first measured how badly the old models transferred, then retrained from scratch instead of trusting them.
Accomplishments that we're proud of
- Raising the main-round score from the starter's 30/60 to 57.15/60, with the untouched audit half (57.27) confirming it.
- Spotting why our main models failed on the new data (the lag-7 to lag-3 shift) and recovering from 9.11/20 to 19.05/20 within the adaptation window.
- Fully reproducible entries: they run on the CPU in about a minute and match our submitted forecasts to within $10^{-15}$.
What we learned
- More data beat more architecture. Attention models, TCNs, bigger LSTMs and late-tick loss weighting all lost to a plain LSTM trained on more examples.
- Ensembles help most when the members make different mistakes: different losses, neighbor features and augmentation all added value; extra seeds of the same model added little.
- Models fitted to one set of patterns can be confidently wrong after a change. Checking which lags still carry signal told us retraining from scratch was the fix.
What's next for House Edge
- Better handling of short histories, still the largest share of the remaining error: encode the gaps between observed ticks directly instead of stepping through missing ones.
- Per-machine adaptation at prediction time: briefly fine-tune a small adapter on each machine's own history, since same-type machines can react in opposite directions.
- Automatic change detection, so the pipeline notices when lag patterns shift and decides on its own whether to retrain.