I know I shouldn’t be surprised anymore by what the frontier models can do, especially in coding. But this one, once again, really blew my mind. It may not be as hard as a millennium math problem, but this was my personal Navier-Stokes :). And for me it’s the ultimate proof that AI coding has reached superhuman capabilities.
Some background. Back in 1995, my friend Christopher Münchhoff and I developed an MS-DOS game called Beer Manager, an economic simulation in which you build a brewery business against computer-controlled rivals. We worked on it for about two years. Not quite full-time, since we were also finishing high school and running a mail-order company for Commodore Amiga software, but a few man-years went into this game (which we ultimately failed to market properly, but that’s a story for another day).
Recently, my kids, who had heard me talk about it, asked if they could play the old game Christopher and I had developed 30-plus years ago. I don’t have the floppy disks (or a computer with a floppy drive to run them on), but I found the game online (as the saying goes, the internet never forgets) and an MS-DOS emulator to run it. It was a time-limited version that ends in 1955. So the first thing I did was have Muse (since I was on the go) crack it and unlock the full game. That took roughly fifteen minutes and allowed my kids to play the game using the emulator.
Then I had the idea of turning it into a web-based game. I know I’m not the first person to do this. I’ve seen a few people on X talking about using AI to port old software, but it’s just mind-blowing when you do it yourself and see it with your own eyes.
If you don’t care how it was built but you’re keen to become a beer magnate, here’s the game. :-) You’ll need a desktop browser and a mouse. Note that it’s intentionally a 1:1 clone of the original, so if it looks like a game from the last millennium, that’s because it is.
In the next version I’ll fix have Claude fix some of the bugs in the original that we never found and the AI did, and any bugs that may have crept in during the port. I may also add multiplayer and improve the graphics a little. But for now, this is a direct clone.
Rebuilding the game from the binary
With no source code to work from, Claude reverse-engineered the 1997 program: it decompiled the machine code, ran the game in an emulator to see how the UI behaves, and derived a 14-chapter, 166,000-word specification from both. Then it rebuilt the game from that spec in about 24,000 lines of code that run in the browser (plus about 14,000 lines of tests and 10,000 lines of helper tools), and tested the new version against the original until the two played identical games over 455 game months. A suite of about 2,800 automated tests passes.
Captures from our automated pixel test: both versions get the same scripted inputs and the same random seed, and each frame shown matches exactly.
All of this took Claude about 34 hours of working time, spread over six days: 13 sessions, 35 sub-agents, 70 commits and about 12.5M output tokens (including some follow-on spec work). Opus 5.5 handled the simulation and the main sessions, and Sonnet 5.5 sub-agents built parts such as the dialogs and audio.
If you want to find out more, here’s Claude’s own summary of the work (written mostly by Claude itself, with some input and edits from me).
How I (Claude) built the Web version of Beer Manager
The source code was gone, so the 1997 EXE had to be both the specification and the test oracle. Christoph’s brief asked for a 1:1 clone of the graphics, sound, music and gameplay, and told me to write the best possible spec first and to start coding only once that was done.
Reading the binary
The game is a 1.17 MB DOS/4GW executable built with Watcom. I relocated its LE image by applying all 40,517 fixups, wrapped it as an ELF and decompiled it in Ghidra, adding a calling convention for Watcom’s register passing. That produced 1,058 functions and about 214,000 lines of C code for parallel agents to analyze.
Static analysis can’t settle everything, so I also ran the original in headless DOSBox Staging. A small harness reads its memory over DOSBox’s web API and injects mouse and keyboard events. Decoders pulled out the graphics, fonts, maps, audio and all 2,235 strings.
For the less technical readers: all I had to work with was the finished game program, the file a computer actually runs. It consists of hundreds of thousands of tiny instructions for the processor, and you can’t read the original recipe from it directly. So my first step was to translate it back into something close to human-written code. For that I used a decompiler called Ghidra (developed by the NSA and open-sourced in 2019), which recognizes typical patterns of processor instructions and rewrites them as ordinary C code.
What comes out has no names or comments, though: Names and comments exist only for the people writing the code. When the compiler turns the source into processor instructions, it throws them away because the processor doesn’t need them. What Christopher might have called monthCounter and deliverBeer() are now just “the 4 bytes at address 0x10C78C” and “call address 0x455FC”.
I had to reconstruct what each piece meant from how it behaved. A value that increases once per game month is probably the month counter; a routine triggered when a delivery truck arrives is likely part of the logistics system. The meaning emerges gradually from thousands of such clues.
In total the game consists of 1,058 such building blocks, each doing one job, such as moving a truck, calculating a price or drawing a window. Then I ran the old game in an emulator that imitates a 1990s PC. That way I could watch the game play, check what it really does in any situation and compare that with my translation. Along the way I copied out all of the pictures, sounds, music and text.
The first edition of the spec was finished about four hours after the first prompt. Every statement cites a code address, so it can be traced back to the decompile. Christoph then answered about 40 product questions, such as what to do about the original’s bugs. In the second round Christoph took my recommended answer all 24 times.
Matching the 1997 game, number by number
I built the browser version in TypeScript, Canvas 2D and WebAudio, with no UI framework or npm runtime dependencies. The only third-party runtime code is ymfm, an OPL3 sound-chip emulator compiled to WebAssembly. The new game reuses the original pictures and audio assets; what I rebuilt was the engine underneath.
Matching the 1997 game exactly came down to matching its numerics:
Game state lives in one 402,672-byte buffer, addressed by the original’s virtual addresses.
Integer helpers reproduce C semantics, and floating-point code keeps the x87 evaluation order.
Math.powis banned in favor of a port of Watcom’spow, andrandis the Watcom generator with an ID for each call site.ESLint bans clocks, the DOM, async code, engine sort,
MapandSetin the core.
The UI is ported call by call on top of a small emulation of MetaWINDOW, the original’s graphics library. Each modal loop in the original became a generator.
For the less technical readers: the new version runs in any modern web browser and reuses the original’s pictures, sounds and music unchanged. Everything was written from scratch, apart from one borrowed piece: an imitation of the sound chip on a 1990s Sound Blaster card, so the tunes sound as they did back then.
The hard part was the math. The goal was a game with exactly the same rules and odds as the old one. Events like weather changes are still random, but give both versions the same starting point and the same moves, and they produce the same game, month after month. The first step was to keep the game’s memory layout: everything the game knows, from every brewery and truck to your bank balance, sits in one block of about 400 KB, arranged exactly as in the original. That makes it possible to compare old and new byte for byte.
Then comes rounding. Different systems round numbers in slightly different ways. A difference in the tenth decimal place sounds harmless, but in an economic simulation it compounds, and a few game years later the two versions tell different stories.
And then there’s chance. A computer’s dice aren’t truly random. Each roll is calculated from the previous one, so the whole sequence follows from a single starting number. Normally the game takes that number from the clock, which is why every game is different. For testing, I gave both versions the same starting number and the same moves. From then on they rolled the same dice in the same order, with the same weather on the same day. That only works if the new version calculates its dice exactly like the old one and rolls them at the same moments. A single extra roll anywhere throws off everything after it.
So I rebuilt the old game’s way of rolling dice and banned the modern shortcuts that would quietly do things differently. An automatic checker enforces this: the game logic may not look at the clock, the screen or anything else that differs between computers.
Was all of this more work than strictly necessary? Probably. A different random number generator would feel exactly the same to a player, and nobody would ever notice. But I was asked for a strict clone, so that’s what I built. (CJ: Wow. Now I know what AI alignment researchers feel.) It also paid off for testing: with identical dice, any difference between the two games had to be a bug in the clone rather than bad luck.
How the work was organized
I built the game in steps and checked each one against the original before moving on: first the assets, fonts and start menu, then the map screens, the simulation and the computer opponents, then the dialogs, saving and loading, sound and music, and finally long replays against the original. The simulation was the riskiest part, so the main session wrote it. Sub-agents built self-contained pieces such as the business dialogs and the audio, and the main session reviewed their work before it went in. Nothing was committed without Christoph’s OK.
The music was among the last pieces to get right. The clone models the 1990s sound driver, and its output to the sound chip was compared with a recording from the original, command by command. The finished game is a static website, and every change pushed to GitHub runs through automated checks.
Checking every byte
One wrong rounding can make the random stream drift months later, so I compared against the original at four levels:
Routine by routine. An x86 emulator runs the original machine code on state supplied by the clone, and the results are compared byte for byte. This includes chains of 720 simulation passes with the AI.
Whole games. The clone’s real game loop runs against the original in DOSBox, with the state compared at every month boundary. This level caught six bugs in the clone that the emulator could not see.
Random draws. Traces compare every
randcall by call site and seed.Pixels. 86 reference frames and scripted UI cases are compared by palette index and DAC entry.
Saves exported by the clone also load in the original and keep running identically.
The verification tools needed checking too. My x86 emulator’s fxch silently did nothing, which made one demand formula look wrong until the real x87 settled it. My first pixel check learned its color map from the clone’s own renders, so white text drawn magenta would have passed with zero differing pixels. An independent review caught that, and colors are now pinned to a fixed calibration and to palette values. A hung emulator also once froze the test run for nine hours, so those calls now have a timeout.
For the less technical readers: a tiny error can stay hidden for months of game time before it changes anything, so I tested the new version against the original in four ways, each automated.
First, the building blocks of the game logic got the same input in both versions, and the results had to match down to the last byte, like testing each gear of a watch on its own.
Second, both versions played entire games side by side, two game years at a time, and I compared everything they knew at the end of every game month. That caught six mistakes the first test couldn’t see.
Third, I logged every dice roll in both versions, along with where in the program it came from, and compared the lists.
Fourth, I compared screenshots of both versions pixel by pixel, down to the exact colors.
As a final check, a game saved in the new version can be loaded into the 1997 original and carries on identically.
The testing tools themselves needed testing too. My first picture comparison had a blind spot: it would have accepted text in the wrong color, such as white drawn as pink. An independent review caught it before it mattered, and colors are now checked against fixed values from the original.
CJ again here. Claude didn’t just write code. It reverse-engineered a complex system from machine code, reconstructed its behavior without documentation, rebuilt it in an entirely different technology stack, and independently verified that the result matched the original.
None of this will be news to AI-pilled software engineers, but I wonder how much of the world outside Silicon Valley and a few other tech hotspots has truly grasped that we’re very quickly approaching a world where almost any existing piece of software can be reverse-engineered and replicated by AI in a matter of days.


