Why this exists
On the night Italy got knocked out of the third World Cup in a row, I had two options: process the grief like a functioning adult, or open a code editor at 2 AM. I opened the code editor.
Other people journal. Some go to therapy. I built a 100,000-run Monte Carlo simulator of a parallel universe where the Azzurri are exactly where they belong, at the World Cup, just to watch the numbers tell me they would probably lose in the Round of 32 anyway. Catharsis is a flag toggle now.
So this is, technically, a statistical football engine. Emotionally, it is a digital coping mechanism with a Bayesian model attached. There is a button that puts Italy back into Group B in Bosnia's place. I press it a lot. It helps.
“Italy isn't at the World Cup, so I put them back in myself.”
What it does
Hit Simulate and the browser plays out 100,000 complete World Cups (group stage, best third-placed teams, Round of 32, all the way to the final) and aggregates them into a win probability for each of the 48 teams. One sampled run is kept aside and replayed as an animated “Tournament Cinema”, clearly labelled as one universe out of 100,000.
Around the core simulation there is a full product: a probability dashboard with phase-by-phase reach tables, a 0–100 Strength Score per team, head-to-head matchups with expected goals, and stackable what-if scenarios (injuries, suspensions, chaos factor) that re-run everything and encode the exact scenario in a shareable URL.
The first answer is deliberately simple: after 100,000 tournaments, who wins most often? Instead of pretending there is one certain future, the dashboard exposes the distribution behind it — from lifting the trophy to reaching each individual round.
Probabilities explain what tends to happen, but they do not feel like a World Cup. So the simulator saves one of those 100,000 universes and turns it into Tournament Cinema: the bracket unfolds match by match, with every sampled upset allowed to rewrite the path to the final.
Sometimes the interesting question is smaller than an entire tournament: what happens if these two teams meet tomorrow? Head-to-head mode isolates that matchup and translates the model into win, draw and loss chances, together with the expected goals behind them.
Then reality interferes. A key player gets injured, another is suspended, or the tournament becomes unusually chaotic. These what-if scenarios can be stacked and the full simulation rerun immediately, making the cost of each change visible instead of leaving it to intuition.
Under every prediction sits the same common language: a 0–100 Strength Score. The teams view brings all 48 national sides back into one frame, so the assumptions feeding the simulation remain visible and comparable before the first virtual ball is kicked.
The engine
Every match is modelled as a bivariate Poisson in the Dixon-Coles style: each team has an attack and a defense parameter, corrected for the systematic overestimation of low-scoring draws, nudged by real head-to-head history, and shrunk so favourites never become invincible. The Monte Carlo loop then samples actual results, it advances the sampled winner, never the favourite, which is why repeated runs crown different champions.
The attack and defense parameters are not guessed: they come from a hierarchical Bayesian model fitted offline with PyMC on roughly 49,000 international matches since 1872, with time-decay weighting and Elo-anchored priors. The browser only loads the exported JSON, no Python, no fitting, no backend at runtime. All 100,000 tournaments run inside a Web Worker, so the UI never freezes.
The Italy button
The flagship what-if: Italy didn't qualify, knocked out by Bosnia on penalties in the playoff. One toggle puts the Azzurri into Group B in Bosnia's place, the exact slot they would have taken, and re-runs the whole multiverse. The model stays honest: no bonus, no sentiment, just the parameters Italy earned on the pitch. The numbers are rarely kind. I keep pressing it anyway.
How it actually ended
A while after I shipped this, the real World Cup ended, and Spain lifted the trophy, exactly the team my simulator had crowned the clearest favourite: the highest win probability of all 48. A bunch of friends messaged me to say thanks, they'd trusted the numbers. And it wasn't a fluke: most of the teams the model pushed deep into the bracket actually went deep. That's the good news, the analysis really was built on solid data. The bad news is the same news: it means the model was probably right about Italy, too.
“Turns out the model didn't need therapy. I did.”




