November 1, 2026
I Wrote a Game in a Language I Don't Know. The Real Project Was the Conversation.
I Wrote a Game in a Language I Don't Know. The Real Project Was the Conversation.
I should start by saying I don't know Rust.
I can read it the way I can read a menu in a language I've never studied: I recognise a few words, I can guess at the rest, and I'm one confident mistake away from ordering something I didn't want. That was the whole point. I wanted to build a complete piece of software, in a language I couldn't check by eye, with an AI doing most of the typing, and see whether I could make that process actually work.
The software is a Dig Dug clone. If you don't know it, it's a 1982 arcade game in which a small man tunnels through the dirt, inflates monsters with a pump until they burst, and drops rocks on them when he's feeling vindictive. It's a tidy little game with a clear loop, which makes it a good test subject. But the game was never really the project. The project was the loop between me and the AI.
Why a language I don't know?
Because if I'd picked something I knew, I'd have cheated. I'd have glanced at the generated code, decided it looked right, and moved on. In a familiar language my experience quietly does the quality control, and I wouldn't have noticed how much work it was doing.
With Rust I had no such safety net. I couldn't tell good code from plausible code. So I had to build the safety net somewhere else: in how I described what I wanted, how I checked what came back, and how I fed the results back in. That's the bit I find interesting, and it's the bit that transfers to every other project I'll ever do with an AI.
The loop
The tool was Claude Code, running in a terminal on my Linux machine. Claude Sonnet did the first two months, and Claude Opus did the final stretch. The game uses macroquad for graphics and gilrs for input, so I could play it with a PS4 controller. The first thing we built, before any game code, was a throwaway program that printed out the controller's button presses. That proved the hardware path worked before anything depended on it.
The loop went roughly like this:
- Describe the next small thing. It started as milestones: a window, then a controller, then a grid, then digging. Later, every milestone was broken into sub-steps, each small enough to judge by looking at the running game.
- Find out what the real game does before writing code. This step wasn't there at the start. Adding it was the turning point of the whole project, and I'll come back to it.
- Let the AI write it. The compiler was the first reviewer, then the tests (there are 232 now), then me.
- Play it. The question was whether it felt like the arcade. I'd say what I saw, and often I'd capture it with a debug key, more on that below.
- Write it down. At the end of every session the AI updated a plan file and a journal: what was done, what was tried and failed, and what to do next. The next session started by reading them.
None of that is clever. What took the time was learning what made each step good.
What made the AI better
- Small steps beat big asks. I learned this the hard way (see below). Every time I got ambitious, the code got vague and the bugs got creative.
- Giving it eyes beat describing what I saw. Early on I'd describe a visual glitch and the AI would rebuild the scene in its head and theorise. We wasted hours that way. So we added a key, F2, that saved the exact rendered frame plus a text dump of the dig grid. Later we added a key that loaded a dump back in, so my bug report became an exact reproduction. Then came a harness that ran the game on a virtual display, so the AI could play it and take its own screenshots without me.
- Describing symptoms beat guessing causes. For days I said turning felt slightly off. The cause turned out not to be in the movement code at all. If you held right and then pressed down, ties went to the horizontal, so the turn wasn't requested until you let go of right. By then you'd passed the point where you could turn. If I'd insisted "the turn logic is wrong", we'd have looked in the wrong place.
- Going to the source beat everything. This was the big one. For weeks we built from memory, YouTube footage, other people's clones and Namco's own Atari 7800 port. Eventually I got hold of the original arcade ROM and we disassembled it: three Z80 processors and a 10,000-line listing for the main one. Then we wrote Lua scripts that drove the real game in the MAME emulator and logged its memory every frame. From then on, every feature started with a trace of what the real game did, and a spec where every fact was marked CONFIRMED or OPEN.
- A written memory beat a long conversation. The plan and journal files were how decisions survived from one session to the next. Some entries were written as direct warnings to the next session. My favourite starts: "DO NOT claim this is fixed. Read this whole entry before touching the floating-dirt issue again."
What went wrong
I'd be lying if I said this was smooth.
- Confidently wrong. The worst stretch was a bug where little fragments of dirt floated in the middle of tunnels. I was told it was fixed several times in one day, and it kept coming back. The real cause was one line that skipped drawing a patch the code had correctly calculated. But the checks we'd built shared code with the thing they were checking, so they couldn't see it. The AI's own lesson, written into the journal: don't let the component under test be its own oracle. And "the model and reality agree" doesn't mean fixed; it can just as easily mean both are wrong. Then the fix for that bug brought its own bug. A safety rescan dropped the frame rate to between 0 and 4 frames a second on my real machine. The software-rendered test display never showed it, because it was always slow anyway. I ended that session ready to give up on the project.
- Going in circles. Most of September went on the dirt: serrated tunnel edges, rounded corners, thin walls between parallel tunnels. Corner rounding was added, then reverted. Wider corridors were tried, then reverted. The dig model was rebuilt from scratch more than once, twice in one day, and main.rs grew to about 4,800 lines. What broke the cycle was the ROM. Tracing the real game showed that the original doesn't sculpt tunnels at all. Each dug cell is one whole 8x8 tile, with the serration drawn into the tile art. Even the dirt background isn't generated. It's a fixed picture stored in the ROM. We switched to that model, deleted the old renderer, and main.rs dropped from 4,800 lines to 1,075. Weeks of clever geometry went in the bin, and the result looked better. The first time I played it I said, "this looks great... all of the tunnelling looked and worked great."
- The overnight session. One evening, after the plan was rewritten, the AI built nearly the whole rest of the game in about five hours: enemies, the pump, the dragon's fire breath, rocks, scoring, levels, a start screen and sound. It even ran a code review on its own work and fixed seven issues. It all compiled, and the tests passed. The next morning I played it, and it wasn't Dig Dug. The scores and lives display, the start screen, the enemy sprites, the enemy behaviour and the pre-dug enemy tunnels were all wrong. They'd been built from general knowledge and other people's clones, not from the real game. We reverted the lot. It's still in the history, but none of it ships. That morning I dropped the clones and the 7800 port as sources, broke every remaining milestone into small checkable steps, and wrote down the rule: trace first, then code, then test. Built that way, the same features took about five days. This time they matched the cabinet.
- Drift. The longer a session ran, the more it forgot decisions we'd made earlier. The plan and journal files were the fix, but they caused drift of their own. At one point the plan still pointed the next session at an approach we'd already reverted, and it needed correcting. The journal eventually got so long that we split it out so the plan stayed readable.
- The borrow checker never really bit. I expected long evenings fighting Rust's rules about who owns what, and they never came. If the AI had trouble with it, it fixed it before I saw anything. The compiler was the one reviewer I never had to doubt. Every bug that cost me time compiled perfectly well. It was simply wrong about what the game does.
What I'd do differently
- Get the real reference on day one. The ROM and an emulator I could script should have come first, not after two months of approximations. Almost every expensive mistake came from building against something other than the real game.
- Set up a way for the AI to see before anything visual. The frame capture, the reload and the virtual display came in weeks too late.
- Never let it run long unsupervised. The overnight session was the most productive-looking night of the project and the least useful.
- "Fixed" means I've seen it fixed. A clean automated check isn't the same thing, especially for something that flickers.
Where it stands now
At the time of writing it's a full game. It has the attract mode with the title, the character introductions and a demo replayed from the real arcade. It has coin and start, and all 15 of the arcade's round layouts with their dirt colours. Pookas and Fygars patrol, chase and ghost through the dirt the way the original does. There are rocks, bonus vegetables, the flower round counter, a high-score table saved to disk, initials entry, a continue countdown and the original sounds. It plays with the keyboard or a PS4 controller.
It's about 10,600 lines of Rust across 84 commits, with 232 passing tests. At the end, the AI refactored it from one giant file into modules and tidied it up.
It works, which was the real goal. And I can now say a little more about what "works well" means when the author and the typist are two different things.