UYLLII

Blog › Game design

Game design

Balancing an idle game with a simulator (and the month my bot cheated)

By David3 min read
Genesis feature graphic

An idle game is a set of curves. Prices grow, production grows, prestige rewards grow, and the game is fun only if those curves cross at the right moments over days and weeks. You can't playtest a 40-day game by hand every time you change a number.

So Genesis is balanced by a simulator: a headless copy of the game engine with a bot that plays it, plus an auto-tuner that adjusts the numbers until the bot's experience hits the targets. This post is about how that works, and the month it spent confidently measuring the wrong thing.

Balance as knobs

Hand-editing hundreds of prices and multipliers doesn't scale, and it drifts. Change one curve and three others are suddenly wrong. Instead, the whole game's pacing reduces to a few dozen meta-knobs: how fast the first tier pays off, how steep the strand's costs are, how big a prestige reward is relative to the run. A retune() function regenerates every literal from those knobs in one consistent pass.

The tuner does coordinate descent over the knobs: nudge one, re-run the sim, keep it if the score improves. The winner is baked into the game's defaults. Nobody hand-edits a balance number.

Making the sim fast mattered. One round of optimisation (threading an aggregate through, batching taps, removing allocations from the gate checks) made it 66 times faster, so a tuning run that took an evening started taking minutes.

The bot that bought from an invisible tab

For about a month the tuner produced numbers that felt wrong in play, and the sim insisted they were right. The cause turned out to be embarrassingly simple.

Nucleotides (the strand's currency) started accruing from the first second. The Mutations tab where you spend them is hidden until your first Extinction. The bot didn't know about tabs. It started every game buying strand rungs no human could see, opening with 14 rungs and a 118× tap multiplier.

Every bake for weeks was fitted to that player. The rule I took from it: the model may only buy what the UI offers. The bot now asks the same visibility functions the interface uses.

Other things the sim got wrong, each found the hard way:

Where this leaves me

Every one of those bugs was found, fixed and covered by a test. And every fix moved the numbers enough that the previous tuning no longer meant anything. I'd tune, find out the bot had been measuring a player who couldn't exist, fix the bot, and start tuning again.

Underneath that is a harder problem: an idle game with no ending has no finish line to tune towards. "Is Chapter 2 the right length?" has no answer when Chapter 2 is supposed to go on forever. So the targets kept moving: 20 days, then "aim for 10 rather than 20", then a new chapter structure, then new targets for that.

I've learned more maths from this game than from anything since university. I haven't yet learned how to finish it. More on that soon.