
The Game Remembered What I Forgot
The source code to a game I wrote in 1993 was gone, so I rebuilt it from the shipped binary, deriving every rule by inference. Days after I finished, a floppy gave the source back — and graded the reconstruction. On what you learn by having to prove a thing instead of read it.
Combat Tanks, a game I wrote in 1993, has medics in it, and I didn’t know.
Shoot a soldier and he might not die. He goes down wounded and lies there in the grass. Another soldier, a healthy one, will walk over and bring him back up. Each soldier can do this exactly once. Spend it and that’s the last time he ever helps anybody, for the rest of the game.
I wrote that. In 1993, in a game that went on to sell past thirty thousand copies through mass-market retail. And I found out about it in 2026 by reading a disassembly of my own shipped binary, one instruction at a time, like a stranger who’d never seen the thing before.
My friend Randy Weems and I built Combat Tanks for Windows 3.1 through Red Herring Software, a company we started mostly so the copyright notice would have something to point at. Two people, one codebase, four hands on it for a year. Thirty-three years later I frequently can’t tell whose hand is on a given line, so I’m going to say “we” for most of what follows and name the exception when the code itself makes it knowable. Randy was killed in a car wreck in 2001. That’s the other reason the attribution matters to me, and the reason I’d rather admit the blur than paper over it.
I got a little nostalgic as I was rebuilding my web site, and went looking for old source code. The Combat Tanks code was gone. I went through every floppy in the closet with a USB drive and came up with nothing, so when I decided to rebuild the game for the browser last month I had one witness to work from: the shipped binary, the same 199 kilobyte Windows 3.x executable anybody who bought the game got on a disk.
A binary is the game with the explanation removed
Compiling a program into machine code throws away almost everything a person put into it. Variable names go. Comments go. The shape of your thinking, the functions you named after the thing they actually do, the note you left yourself in the margin — all stripped. What survives is behavior. The machine keeps what it needs to run and discards what you needed to understand. The game you play remembers about as much about its source code as a red velvet cake does about its recipe.
So you can’t read it. You have to interrogate it.
The loop goes like this. Watch the game do something. Form a guess about the rule underneath. Go find the arithmetic that would produce that rule. Check whether it matches. Be wrong a lot.
And no, I’m not a skilled enough developer to rifle through machine code figuring things out alone. A very heavy dose of AI was instrumental in this effort even being remotely possible.
Bounty scoring came out that way. I’d assumed, the way anyone would, that killing a tank was worth some fixed number of points sitting in a table somewhere. There is no table. When you destroy something in Combat Tanks you take whatever score it had accumulated. A tank that’s been quietly farming kills for two minutes is worth a fortune. One that just spawned is worth almost nothing. The economy is entirely made of what everything else has already earned, and I derived it by watching numbers move in ways a fixed table couldn’t explain and then hunting for the multiply that wasn’t there.
Every rule I recovered came with a small anxiety attached, because inference is not proof. I could be pattern-matching. I could have found an arrangement of arithmetic that happened to fit and still have the reason wrong. And I really wanted to get it right. I wanted to recover and share the original game in a browser exactly as it played in Windows back in 1993.
Then I said goodbye in public
The browser version went live at the end of August. I wrote up the vault entry for it and put a line in about Randy, and in that line I said the original C source was gone, that I’d finally read every floppy in the closet and it wasn’t there, and that I’d rebuilt the game from the binaries instead, sprite by sprite and rule by rule.
I meant that line as a closing. It read like one.
Four days later the source came back.
Not from the closet — from a Greaseweazle, a small gadget that stands in for the floppy controller and captures raw magnetic flux transitions straight off the drive head, leaving the decoding to software afterward. An ordinary drive hands you a sector or an error and nothing in between. This hands you the waveform and lets you argue with it. On one of the 3.5" disks it pulled back was Combat Tanks v1.0, October 1993 — the shareware build, one version behind what shipped, every source file intact.
The crazy part is it arrived after the reconstruction was finished. Four days too late to help me. Which meant it couldn’t teach me the game. It could only grade me on it.
It agreed
The medics are in GROB.CPP, in the function that runs when a soldier bumps into something. The condition checks that this soldier still has his one rescue, that the other one is wounded, and that he’s facing roughly the right way. Then it spends the rescue and adds the energy back. Sitting beside it, in our own words:
// heal a wounded comrade
The bounty scoring is four lines. When something dies it hands its accumulated score to whatever killed it and zeroes itself out. The comment is written from the point of view of the thing being destroyed:
// give the object that killed me my score
That one stopped me for a while. Not because it told me anything I hadn’t already worked out, but because of the me. Some twenty-two-year-old sat there and wrote the comment in the voice of a dying enemy tank, and then shipped it, and then it sat on a magnetic disk in a closet for three decades waiting for nobody.
Another example of what’s lost to faded memory is this — there’s a table in the code called xOffset that positions the rotor hub as a helicopter’s blades sweep around. Eight values, hand-tuned, in the fixed-point notation we used for everything. I had reconstructed that table by measuring sprite offsets out of the binary and having Claude squint at the numbers until the shape looked right. The array in the source is the same eight numbers.
I ran a mechanical check on the parts a computer can verify. The game’s resources — its bitmaps, its menu, all eleven dialog layouts — compile from a script that I’d had to rebuild from scratch, because that file didn’t survive on the disk either. Twenty-five of twenty-five came back byte-for-byte identical to the 1993 build.
Left, the shipped Windows game. Right, the browser rebuild, reconstructed from the binary before the source came back.
What the guessing was for
I understand this codebase better than I would have if the disk had been in the closet all along, and I’ve been trying to work out exactly why that is.
Reading source code gives you the what, fast and cheap and complete. It’s the whole point of source code, human-readable commands to be converted for machine use. With source code somebody already did the thinking and wrote it down for you, and you get to skip the derivation entirely, which is a magnificent deal in almost every circumstance.
Reconstruction from a binary executable doesn’t offer that deal. Every rule has to be earned as a hypothesis, tested against evidence, and held provisionally until something confirms it. You end up knowing that soldiers heal each other. You also know what else the rule couldn’t have been, which observations would have killed it, and where the seams are. That knowledge has a different texture. It’s slower and more expensive and it sticks to your hands. It’s trying to figure out if that’s a hint of almond or vanilla in that red velvet cake without really knowing for sure.
Everything the machine does, and nothing about why.
I’d have shipped the browser reboot of the game in a day with the source. It took a week without it. I want to be careful not to launder that into a lesson about how loss is secretly a gift, because it isn’t one, and given the trade I’d take the disk every time.
But the week wasn’t waste. Going through a round of reverse-engineering before the source turned up, I got to reacquaint myself with code we’d written thirty-three years ago, one rule at a time, the way you catch up with an old friend.
The question I got asked in the middle of it
None of this would have happened at all except that a stranger emailed me out of nowhere while I was thinking about it.
He’d played Combat Tanks as a kid. He mailed us money for the unlock code — actual money, in an envelope, to a P.O. box — and as a teenager he rebuilt a good chunk of the game in Flash from memory, because that’s what you did. He works in software now. He has young kids, and he’s teaching them to program the long way around, through Scratch and then Python.
His question was about when to hand them the powerful tools. He compared it to giving a calculator to a kid who hasn’t fully ingested how to add or subtract by hand, or PEMDAS (Parentheses, Exponents, Multiplication, Division, Addition, and Subtraction). And then he said maybe that’s one of the central questions in parenting, which I’ve been thinking about a fair amount even though I’m not a parent.
I don’t have a clean answer. What I have is one data point, and it’s this essay. I spent a week deriving rules from a binary with a lot of machine assistance, and I came out of it knowing my own game more thoroughly than the twenty-two-year-old who wrote it did. The tools didn’t skip the derivation for me. They made the derivation survivable — a week instead of a year — and I still had to do every hypothesis myself, because the machine had no more access to 1993 than I did.
That might be the distinction he’s looking for, or it might be a comfortable story I’m telling because it flatters what I just did. I genuinely can’t tell from inside it.
The joke that outlived everything
In the middle of GROB.CPP, in the code that decides what a soldier does when he runs into something, there’s this:
// soon to be the butt-sniff algorithm
Underneath it are two lines that pick a random number 0 to 3, one of the four cardinal directions, and walk that way for a while. Placeholder logic. Something to keep the soldiers moving until we came back and wrote the real thing, the one where they’d track each other around the map by scent, which we had clearly spent some time discussing and had clearly found extremely funny.
We never came back. The game shipped, sold thirty thousand copies, got reviewed, went out of print, and passed into whatever afterlife shareware games get. The soldiers have been stumbling around in random directions the entire time, in front of every one of those thirty thousand people, and not one of them ever knew there was supposed to be something better.
The browser version still wanders at random. I checked the source and left it alone.
Some to-do items you finish. Some of them turn into the thing itself.