Donkey Kong's Luck Is Made of Spare Time
A lot of Donkey Kong is chance. Will this barrel take the ladder? Will Kong throw a wild one? Which way will the fireball wander? Each of those choices starts with a random number, and the arcade board that runs the game has no way to make one. There is no dice chip, no noise source, no clock it can ask for the time.
So where does the luck come from? The answer in the original 1981 program is odd and rather elegant: the game measures how much spare time it had during the last sixtieth of a second, and uses that. This article walks through that code, and the way it lets the randomness be switched off entirely.
The recipe
Once every frame, the game updates one byte of memory that everything else treats as its random number. The update is three numbers added together:
- The last random number. Each new value builds on the previous one.
- A frame counter, which simply goes down by one every frame.
- An idle counter, which is where the luck comes from.
Only the last eight bits are kept, so the result is always between 0 and 255.
That is the entire generator. It lives at address $0057 in the program ROM
and is six instructions long:
ld a,(random) ; last frame's random number
ld hl,frame_counter
add a,(hl) ; + the frame counter
ld hl,idle_counter
add a,(hl) ; + the idle counter
ld (random),a ; that is the new random number
No multiplying, no table of scrambled values, no secret seed. The program never even reads the Z80's R register, the one counter inside the processor that changes on its own.
Where the spare time goes
To see what the idle counter is counting, it helps to know how the game spends a frame.
Sixty times a second the video hardware interrupts the processor, and everything that makes the game go happens then: moving Mario, rolling barrels, checking for collisions, updating the score. When that work is done for the frame, the processor drops back into a small loop and waits for the next interrupt. Each time around that loop with nothing to do, it adds one to the idle counter.
So the idle counter grows by however many empty laps fit into the time left over. A quiet screen leaves lots of spare time. A screen full of barrels and fireballs leaves less.
Running the original program under a test script that logged the idle counter every frame shows exactly that:
Each barrel on screen costs the processor about three or four laps' worth of time per frame. And even when nothing changes, the count wobbles by a lap or two from one frame to the next, depending on exactly where in the loop the interrupt lands.
That is the trick. Every barrel, every fireball, every step Mario takes adds a little work, the work changes the spare time, and the spare time feeds the random number. The luck of the next barrel depends on everything currently on the screen.
Turning the luck off
There is a catch. Nothing in the recipe comes from outside the program except the player's inputs. Start the board from power-on, give it the same inputs on the same frames, and the work done in every frame is identical, so the spare time is identical, so the random numbers are identical. An emulator, which runs the board exactly the same way every time, makes that easy to test, and it held every time:
| Test | Result |
|---|---|
| Two runs of the attract mode demo, no coins | Identical, frame for frame |
| Two games with the same coin, start and joystick, frame for frame | Identical |
| The coin dropped one frame later | Different random numbers before the game even starts |
| Holding down for ten frames while standing on a girder | No difference at all |
| Holding right for ten frames instead | Random numbers drift apart within two frames |
The attract demo is the giveaway: with no player, it plays out exactly the same way every time. Nothing else feeds in.
In a real arcade, the thing that varies is you. The frame you drop your coin, the frame you press start, every step and jump. Only inputs that make the game do something different count. Pressing down while standing on a girder changes nothing, because the game has nothing extra to do. Taking a step changes the work, the work changes the spare time, and from then on the random numbers run along a different track.
Is it any good?
For a generator this simple, it does its job well. Across more than 367,000 frames of scripted play, each of the four possible values in the bottom two bits came up between 24.9 and 25.1 percent of the time. At the ladder tops, where barrels decide whether to come down at you, the bits the game uses were just as even, and one frame's value said nothing useful about the next.
It does have one weakness, and it shows up when the screen is calm. If the spare time is exactly the same lap count frame after frame, the frame counter and the idle counter add the same amount each time, give or take a steady step, and the bottom bits fall into a loop. On the "how high can you get" screen before each life, with 142 idle laps every frame, the bottom two bits ran 1, 2, 0, 3, 3, 0, 2, 1 and then repeated exactly, eight frames at a time.
In play the pattern mostly washes out, but not completely. With Mario standing still for a long stretch, the lowest bit matched its value from four frames earlier 61.5 percent of the time instead of 50. Moving around brought that down to about 54. Whether a player could ever feel that is another question.
What the luck decides
The research notes list each place that reads the random number. Those seen in action in the test runs include:
- whether a barrel at the top of a ladder comes down;
- whether Kong's next barrel is a wild one that bounces down the screen (one throw in sixteen);
- which way and how fast a wild barrel bounces at the lower difficulties;
- parts of how fireballs move;
- whether some hammer smashes are worth 300, 500 or 800 points.
According to the code, a few routines skip the random number and read the idle counter directly, including one that paces Kong's throws once the bonus timer is half gone. Either way, the game's luck is being stirred by how many things are moving at once, and by every move you make.
Credits and further reading
- Kef Schecter and contributors, furrykef/dkdasm, the annotated disassembly of Donkey Kong. Every address here was checked against the original ROM.