The first commit is a liar

prologue origins, match-engine

Git will tell you this project began on 16 April 2025, with a commit called Initial ME version. Git is lying — or rather, git recorded the day I tidied up, which is not the same thing as the day I started.

The real start was 2024, and it began as an argument I was having with myself about how a football match ought to be simulated. I had played these games for the best part of twenty years — FIFA for arcade clarity, Football Manager for depth, Hattrick for the weekly rhythm, TrophyManager for the particular pressure of having other humans in your league — so I had opinions. Opinions are cheap, though. I wanted to earn mine.

So, sketches first. Rough models of how possession turns into chances and how chances turn into goals. I read through open-source football sims on GitHub too, not to lift a codebase but to see which abstractions survived contact with realism and which ones collapsed the moment you asked them for a believable number of corners. Then I went back through the games themselves and tried to boil their simulation philosophies down to a short list of principles I could actually hold in my head. Enough levers to produce outcomes you'd believe; not so many that the model becomes folklore nobody can maintain, including me.

Then the boring, useful half. I took publicly discussed Opta-shaped frequencies for real football over roughly two decades and used them to work out how often things ought to happen in a match. Put those alongside the levers I had chosen and you have a model. Whether it's a good model is a separate question, which I answered the hard way: crude simulation functions, run over and over, tuned, run again. The bar was never "this is Opta". The bar was that someone who watches football wouldn't laugh at the scoreline.

And then I stopped. The day job won for a while, as it does.

When the itch came back it came back with a clearer brief, which I think is the most useful thing that happened in all of this. Build a clean v1 engine. Then build a game world around it. If the world attracts anybody at all, spend the time on a genuinely realistic engine later. Ship the loop first, deepen the simulator once the loop has proved it matters.

Which brings us back to 16 April. That day is passing numbers, shot selection, set pieces, weather, substitutions, ratings, and a CLI contract — feed it JSON, get a match back. Not a product. A thing I could argue with in tests. Alongside it I started writing down what a game would need before I'd be happy to stop playing TrophyManager and play my own thing instead.

That list turned out to be considerably longer than the engine 😄. More on that in a fortnight.

← All entries