What is inside an ARC-AGI-3 game file

We opened an ARC-AGI-3 game file: 2,060 lines of runnable Python with 26 of 34 functions renamed to random letters. What the ARC-AGI-3 game source shows.

0:00
What is inside an ARC-AGI-3 game file

The first ARC-AGI-3 game arrived on this machine as a single Python file: 2,060 lines, 105,874 bytes, downloaded in 1.2 seconds with no account and no key. Open it and the first thing you meet is a class called hbuhvkxlhc.

That is the whole character of the ARC-AGI-3 game source. It is real, runnable, readable code, and every name that would tell you what it means has been replaced with ten random letters.

How an ARC-AGI-3 game file gets onto your disk

The toolkit is a pip install, and in its default mode arc.make("ls20") does not talk to a remote game server. It fetches the game’s metadata, downloads the source, writes it to environment_files/ls20/<version>/ls20.py, loads the class out of that file with exec, and from then on every step runs in your own Python process. We covered the install and the first run separately. The point here is what lands.

Two files land. metadata.json holds the title, the tags, the version hash and the human baseline for every level. ls20.py holds the game. There is no compiled blob, no asset bundle, no network call at play time. If you delete the directory, the next make() downloads it again. The version hash in the path matters: a revised game downloads beside the old one, never over it, and the id the toolkit reports carries the hash, ls20-9607627b, so a run can be pinned to the exact source it was measured against.

What the obfuscation in ARC-AGI-3 game source hides, and what it leaves

Counting is the fastest way to see the policy. ls20.py defines 34 functions, and 26 of them have names like wgxrzqzazj. It defines 5 classes, and 4 of them are scrambled the same way. The sprites are looked up from a dictionary by 35 ten letter keys, so sprites["gngifvjddu"] is as descriptive as it gets. Level data keys, the ones a game uses to store its own parameters, are also scrambled, with two exceptions worth noting below.

What survives is everything the engine requires. The game class is Ls20(ARCBaseGame), on line 1,765. The methods the engine calls are still called __init__, step, render_interface and on_set_level, because the engine looks them up by name and would not find them otherwise. The engine’s own vocabulary survives too: Level, Sprite, Camera, get_data, set_position, clone. So you can read the shape of the game perfectly. You can see that the constructor creates a Camera 16 pixels wide and 16 high, that the game declares available_actions=[1, 2, 3, 4], and that it keeps a list of four rotation values, [0, 90, 180, 270], next to a list of four scrambled sprite names. What you cannot read is what any of that is for.

Two level data keys were left in plain English: "StepCounter" and "StepsDecrement". They feed a user interface element that draws a step budget on screen. That is a small tell about how the game works, and it is the kind of thing a determined reader would collect across all 25 public games.

How ls20 builds its seven levels from 36 sprites

The level definitions are the most readable part of the file, and they are pure data. There are exactly 7 calls to Level(, matching the seven entries in the baseline list, and each one is a list of sprite clones placed at coordinates:

levels = [
    # Level 1
    Level(
        sprites=[
            sprites["eqatonpohu"].clone().set_position(1, 53),
            sprites["ghizzeqtoh"].clone().set_position(1, 53),
            sprites["hoswmpiqkw"].clone().set_position(33, 9),
            sprites["ihdgageizm"].clone().set_position(4, 0),

Thirty six Sprite( constructions define the palette of pieces, each with a pixel array, a collision mode, and a set of tags. The tags are scrambled. The pixel arrays are not, because they cannot be: they are the picture. So the one thing you can fully reconstruct from the source is the visual layout of every level, which is also the one thing you get for free by playing it.

This is a sensible design. The board is public by definition. The rules are what the benchmark is testing, and the rules live in the 26 scrambled functions.

Why ARC Prize scrambles the names but ships the code

The technical report gives the reasoning in one line about environment identifiers: “Informally, environments have longer names, but these are not shared publicly to avoid sharing semantic information.” The same principle applied to the code produces exactly what is on disk. Ship the mechanics so the benchmark runs anywhere, strip the words so the mechanics do not explain themselves.

It also fits the way the public set is described in the launch post: “hundreds of original turn-based environments, each handcrafted by a team of human game designers”, published so people can build against them. A development set has to be runnable offline. An obfuscated one can be runnable offline without handing over a written spec of every mechanic.

None of this protects the semi private or fully private sets, and it is not meant to. Those never leave ARC Prize’s servers. The public 25 are the only ones you will ever hold, and they are deliberately the easiest.

What you can and cannot learn from reading an ARC-AGI-3 game

You can learn the engine, and that transfers to every game. Every environment subclasses ARCBaseGame, declares a camera and a list of available action ids, builds its levels from sprites, and implements step(). Read one game and you know how to read all of them, and you know how to write your own. Read the engine files alongside it: base_game.py is 593 lines, sprites.py is 651, camera.py is 350, and between them they are the entire runtime a game can call.

You can learn the layout of every level, which is useful for building a harness that recognises objects, and useless for knowing what to do with them.

You can, with effort, reverse the mechanics of a single game by reading 26 scrambled functions and matching them against what the screen does. People will. It is a reasonable way to build an agent for the public set, and it is also precisely why a perfect score on the public set is not a benchmark result.

What you cannot do is read your way to the private sets. The obfuscation is not the wall. The 110 games you never receive are the wall. The scrambled names just stop the 25 you do receive from teaching a model the vocabulary of the other 110.

The practical upshot for anyone running this locally: treat the source as an engine tutorial and a level atlas, and treat the mechanics as unknown, because on the sets that count they will be.

Share this