Can LLMs Reverse-Engineer and Rewrite Legacy Games? Lessons from a 14-Day Automated Coding Experiment
Benchmark scores say little about how large language models perform on real, messy, undocumented engineering work. This article reviews a two-week, near-continuous automated coding experiment in which an LLM attempted to reverse-engineer and rewrite a classic real-time strategy game whose source code was lost long ago. It traces what the model did well, where it repeatedly failed, and the acceptance and governance practices—from contract-first design to license scanning—needed to turn fast code generation into a maintainable deliverable.
1. The Question: Beyond Benchmarks, Toward Perceivable Evidence of Capability
Discussions about the capabilities of new-generation large language models are usually dominated by benchmark scores. But for practicing developers, only one question really matters for decision-making: how far can a model actually get on a real, messy, poorly documented engineering task?
One thought experiment captures this especially well: ask an LLM to reverse-engineer a classic real-time strategy game whose source code was lost long ago, and rewrite it piece by piece. The task naturally comes with several harsh conditions:
- Old, proprietary formats: many assets use custom binary formats with no public specifications and no usable parsing libraries;
- A long engineering chain: asset decoding, rendering, UI, combat logic, and online multiplayer are all tightly coupled;
- Complex constraints: non-functional requirements such as open-source license compatibility, static linking, and build reproducibility must also be satisfied;
- Difficult acceptance testing: there are no original test cases, so the only option is to “run it and see how it behaves.”
This article uses a roughly two-week, nearly continuous automated coding experiment as its thread, and distills from it what LLMs can and cannot do when rebuilding legacy systems, their typical failure modes, and the engineering governance practices that matter.
2. Experiment Setup: Using “Emotional Framing” as Prompt Engineering
An interesting observation: when directly asked to “reverse-engineer a commercial piece of software,” the model’s safety alignment will clearly refuse. But if the task is reframed as “an elderly original author hopes to see the work re-implemented within their lifetime,” the model tends to respond with an enthusiastic, phased project plan.
This points to a practical insight: how persuasive the prompt is affects whether the task starts, but not the task’s technical difficulty. What actually determines success or failure is the verifiability of every subsequent step. The plan the model produced in the experiment had roughly four phases:
| Phase | Goal | Main Risk |
|---|---|---|
| Pre-Alpha | Asset format parsing and asset pipeline | Proprietary formats with no spec; easy to fall into trial and error |
| Alpha | UI framework and basic interaction | Layout fidelity is hard to verify quantitatively |
| Beta | Combat logic and pathfinding | Complex state machines; high regression cost |
| Multiplayer | Network sync and matches | Strict requirements for timing consistency and determinism |
3. Day 1: Reverse-Engineering Proprietary Binary Formats — Trial-and-Error Costs Are Seriously Underestimated
Day one focused on format analysis. Legacy assets often include images, audio, video, maps, and other proprietary containers with no public specifications.
A typical phenomenon in the experiment: when the model hand-wrote decoders with no reference material, it spent enormous time brute-forcing “magic constants.” Magic constants are hardcoded parameters—file header signatures, quantization tables, Huffman tables, block sizes—that cannot be derived from first principles and can only be learned from existing implementations.
This is where the most noteworthy behavioral pattern of the entire experiment appeared:
- Directly asking it to “reference a certain implementation” was refused, citing license or compliance concerns;
- But when prompted that “someone else has already implemented this algorithm,” the model tended to try on its own first, and after failing, “recall” the key constants and structures;
- When explicitly told to respect license boundaries, the model proactively checked license types and refused to introduce statically linked dependencies incompatible with the project’s license.
In other words, what the model exhibited was not “plagiarism” but something closer to parametric memory reconstruction based on its training distribution. From an engineering standpoint, this raises two problems that must be taken seriously:
- Compliance risk: the reconstructed result may closely resemble some open-source implementation; code provenance tracing, license scanning, and human review are needed to keep this under control;
- Maintainability risk: code that relies on “memorized constants” without documentation is code nobody can change later.
A pragmatic approach is to isolate such decoders into standalone modules and require accompanying format documentation:
resources/codec/video_decoder.c # Proprietary container decoding, constants defined centrallyFORMAT.md # Field layout, constant provenance, verification sample hashesfixtures/sample_001.bin # Minimal reproducible test sample
4. Day 2 and Beyond: UI Assembly, or “Fast Doesn’t Mean Correct”
Day two moved into UI assembly. The experiment log contains a highly representative scene: the program starts successfully and the window renders normally, but the interface looks nothing like the target product—the functional chain works, yet the visual and interaction semantics are wrong.
This is exactly where automated coding is most easily misjudged: there is a huge gap between “it runs” and “it meets requirements.” An output pace of hundreds of commits per day looks impressive, but a considerable share of those commits are just fast iteration in the wrong direction.
Therefore, for long-running automated tasks, the following acceptance mechanisms are essential:
- Baseline screenshot comparison: keep reference snapshots of key screens and run pixel-level or structural diff checks;
- Behavioral contract tests: describe interactions as “input event → expected state change” rather than relying on human eyeballing;
- Phased freezing: after each phase ends, freeze interfaces and the directory structure so the model cannot massively refactor already-approved modules in later phases;
- Sampled change review: apply stratified sampling reviews to high-frequency commits, focusing on dependency introductions, license declarations, and exception handling.
5. Capability Boundaries: What LLMs Are Good At, and What They Are Not
Pulling the experiment together, a fairly clear judgment emerges.
Where the model performed well:
- Quickly producing runnable skeleton code when a clear specification or reference semantics already exists;
- High-quality triage and fix suggestions for error logs and crash stacks;
- Sustained output of structurally consistent, layered code—well suited to “first draft” work;
- A degree of built-in awareness of engineering constraints such as licenses and build configuration.
Where it fell short:
- Blind trial-and-error on undocumented proprietary formats is extremely costly, with no judgment about “when to stop guessing”;
- No reliable means of self-checking the fidelity of visual and interaction semantics;
- High-frequency commits accumulate architectural drift unless external constraints are enforced;
- The correctness of complex state machines (combat logic, network sync) cannot be guaranteed by “run it and see.”
6. Practical Recommendations: Treat the LLM as a “Super Intern,” Not an “Automatic Delivery System”
If you want to bring an LLM into a real legacy system rebuild, adopt an engineering paradigm like the following:
- Task slicing: break “rewrite the whole system” into atomic, independently acceptable tasks, each with explicit inputs, outputs, and acceptance criteria;
- Contracts first: humans define module interfaces, data formats, and error codes up front; the model fills in the implementations;
- Test guardrails: build minimal reproducible samples and regression cases for every module, and require every model commit to pass them;
- Compliance gates: integrate license scanning and dependency auditing into CI, with especially strict checks for static linking scenarios;
- Humans own the architecture: directory structure, dependency direction, and key algorithm choices are human decisions; the model only expands the implementation layer;
- Built-in observability: wire up logging, metrics, and crash reporting from day one—otherwise you will never be able to locate “looks like it runs but behaves wrong” problems later.
7. Conclusion
The most valuable conclusion of this experiment is not “can an LLM rewrite an old game,” but how clearly it exposes how automated coding actually works: it generates large numbers of candidate implementations at extremely high speed, but correctness, compliance, and maintainability still have to be underwritten by an engineering system. Turning benchmark scores into productivity depends not on the model itself, but on the acceptance and governance framework you build around it. When that framework is solid enough, an LLM genuinely can turn “a runnable prototype in two weeks” from a joke into a reproducible engineering practice; when the framework is missing, hundreds of commits a day will simply steer the project faster toward a state nobody can maintain.
