{
  "@context": "https://schema.org",
  "@id": "https://aggr.aymericbeaumet.com/items/hnrss-org/2026-10-29-show-hn-i-turned-doom-into-a-transformer/#webpage",
  "@type": [
    "WebPage",
    "ArchiveComponent"
  ],
  "articleBody": "[![DOOMFORMER: the marine fights a horde of demons under a hellish sky](https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/banner_wide.png)](https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/banner_wide.png)\n\n**Neural networks computed by voodoo dolls inside DOOM maps.**\\\n Every value is read back and checked against NumPy. Tolerance 0.\n\n[![tests](https://github.com/mottopanikeiku/doomformer/actions/workflows/tests.yml/badge.svg)](https://github.com/mottopanikeiku/doomformer/actions/workflows/tests.yml) [![release](https://camo.githubusercontent.com/bd90ae1758c512eefd27c9166c2687910317d20c7e48a052a3b85b95d1b3918e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6d6f74746f70616e696b65696b752f646f6f6d666f726d65723f636f6c6f723d386230303030)](https://github.com/mottopanikeiku/doomformer/releases) [![Python 3.11+](https://camo.githubusercontent.com/96abf9b704f80578ea56dd10cab0d911c56d46dbec347f431ece9cf60ac175ad/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f707974686f6e2d332e31312532422d626c7565)](https://camo.githubusercontent.com/96abf9b704f80578ea56dd10cab0d911c56d46dbec347f431ece9cf60ac175ad/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f707974686f6e2d332e31312532422d626c7565) [![MIT](https://camo.githubusercontent.com/b8cadaa967891081f8f165695470689986c028821dd8a040132f6e661795dc0d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c7565)](https://github.com/mottopanikeiku/doomformer/blob/main/LICENSE) [![Open in Colab](https://camo.githubusercontent.com/eff96fda6b2e0fff8cdf2978f89d61aa434bb98c00453ae23dd0aab8d1451633/68747470733a2f2f636f6c61622e72657365617263682e676f6f676c652e636f6d2f6173736574732f636f6c61622d62616467652e737667)](https://colab.research.google.com/github/mottopanikeiku/doomformer/blob/main/examples/doomformer_colab.ipynb)\n\n[Quick start](https://github.com/mottopanikeiku/doomformer#quick-start) · [Walk a digit](https://github.com/mottopanikeiku/doomformer#walk-a-digit-doom-reads-it) · [The museum](https://github.com/mottopanikeiku/doomformer#the-museum-rewire-one-connection) · [How it works](https://github.com/mottopanikeiku/doomformer#how-it-works) · [What is checked](https://github.com/mottopanikeiku/doomformer#what-is-checked) · [Films](https://mottopanikeiku.github.io/doomformer/) · [Docs](https://github.com/mottopanikeiku/doomformer/blob/main/docs/README.md)\n\n| **10,000 / 10,000**     | **1,355**                     | **0**                            | **4**                                     |\n| ----------------------- | ----------------------------- | -------------------------------- | ----------------------------------------- |\n| MNIST test digits exact | voodoo dolls in one MNIST map | mismatches in 20,000 fuzzed nets | other DOOM engines run the museum exactly |\n\n[![A number is a crowd of voodoo dolls. A weight is a line on the floor. A sum is a light level or a height. An activation is a staircase. Attention is a ceiling. Every value is read back and compared with NumPy: tolerance 0.](https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/ladder.png)](https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/ladder.png)\n\n## Quick start\n\n```shell\npip install git+https://github.com/mottopanikeiku/doomformer   # Python 3.11+, Linux or macOS\ndoomformer hello             # 2 s: a small MLP, every value checked\ndoomformer draw --digit 7    # 15 s: the marine walks a 7 and the level reads it\n```\n\n`doomformer doctor` checks your setup. It builds ACC, the ACS compiler, if it is missing. That needs git, cmake and a C compiler. On Fedora: `sudo dnf install git cmake gcc gcc-c++ make`.\n\nTip\n\nNo install needed for the [Colab notebook](https://colab.research.google.com/github/mottopanikeiku/doomformer/blob/main/examples/doomformer_colab.ipynb). Draw a digit in your browser and DOOM reads it.\n\n## Walk a digit, DOOM reads it\n\n[![DrawPad: the marine walks a 7 across a 28x28 floor canvas, presses READ, and the winning voodoo doll lights a 7 on a 7-segment display](https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/drawpad.gif)](https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/drawpad.gif)\n\nThe marine holds FIRE and inks the floor. Then he presses READ.\n\n1,355 voodoo dolls in the same map run an MNIST network. The winning digit's doll crosses a line. That line lights the digit on the display.\n\n```\n          ▄▄▄▄▄▄▄▄▄▄▄▄▄▄\n       ▄████████████████\n       ████▀▀     ▀████▀\n       ▀▀▀        ▄███▀\n                  ████\n                  ███\n                  ███\n                  ███\n                 ████\n                 ███▀\n                 ████\n                 ▀███\n\nDOOM reads: 7  (right)   -- the winner's doll lit it on the 7-segment display\nEXACT: all 248 values DOOM computed [...] equal the NumPy integer reference (tolerance 0)\nREAD pass: 273 game tics = 8 s of real-time DOOM at 35 tics/s, 3 s wall [...]\n```\n\nPython reads back 248 values and checks every one. With `--digit`, Python presses the keys for you. Without it, you walk and draw yourself. [Full output](https://github.com/mottopanikeiku/doomformer/blob/main/docs/commands.md#doomformer-draw---digit-7)\n\nNote\n\nEXACT means DOOM got the same numbers as the integer network. It does not mean the digit is right.\n\n| run                                     | right           | exact  |\n| --------------------------------------- | --------------- | ------ |\n| first 100 MNIST test digits             | 99              | 100    |\n| 1,000 sampled test digits, one map each | 966             | 1,000  |\n| all 10,000 test digits, tile maps       | 9,716 (97.16 %) | 10,000 |\n\nThe float model scores 97.58 %. The network also trained on the strokes the scripted marine walks. [Details](https://github.com/mottopanikeiku/doomformer/blob/main/docs/drawpad.md) · [Film](https://mottopanikeiku.github.io/doomformer/#drawpad)\n\n[![eight MNIST test digits and what DOOM read: 7 2 1 0 4 9 6 3, all exact](https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/mnist.png)](https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/mnist.png)\n\n## The museum: rewire one connection\n\n[![Two views of one doll lane. Before MUTATE, DOOM reads 7 and the doll has passed its gate. After MUTATE, DOOM reads 1 and the same voodoo doll stands at its gate.](https://github.com/mottopanikeiku/doomformer/releases/download/v0.7.1/museum_mutate.png)](https://github.com/mottopanikeiku/doomformer/releases/download/v0.7.1/museum_mutate.png)\n\nTip\n\n**Play it without Python.** Download [museum.wad](https://github.com/mottopanikeiku/doomformer/releases/download/v0.7.1/museum.wad) ([sha256](https://github.com/mottopanikeiku/doomformer/releases/download/v0.7.1/museum_SHA256SUMS.txt)) and the free [Freedoom](https://freedoom.github.io/download.html) IWAD. Then run `gzdoom -iwad freedoom2.wad -file museum.wad`.\n\nStep on seven floor pads to light a digit. Press READ. 136 voodoo dolls run a tiny network and light the answer.\n\nPress MUTATE and the level rewires one connection while it runs. The same 7 now reads as 1. You can watch it happen: one doll stops at its gate.\n\n```\n$ doomformer museum verify\n7                        pads abc     w_7a +1  DOOM reads 7  scores [4, 6, 3, 5, 4, 3, 2, 7, 3, 4]  EXACT (148 values; 744 tics; [...])\n7 after MUTATE           pads abc     w_7a -1  DOOM reads 1  scores [4, 6, 3, 5, 4, 3, 2, 5, 3, 4]  EXACT (148 values; 744 tics; [...])\n7 after RESTORE          pads abc     w_7a +1  DOOM reads 7  scores [4, 6, 3, 5, 4, 3, 2, 7, 3, 4]  EXACT (148 values; 744 tics; [...])\n```\n\nA self-test version runs exactly in GZDoom, LZDoom, UZDoom and ZDoom 2.8.1. [Details](https://github.com/mottopanikeiku/doomformer/blob/main/docs/museum.md)\n\n## How it works\n\nEvery part of a network becomes a part of the map:\n\n| in a neural network  | in the DOOM map                                                |\n| -------------------- | -------------------------------------------------------------- |\n| a value of 5         | 5 voodoo dolls                                                 |\n| a weight             | a line on the floor; each doll that crosses it adds the weight |\n| a sum                | a sector's light level or floor height                         |\n| an activation (ReLU) | a staircase of gates the dolls must climb                      |\n| attention            | dolls squeezing under ceilings that another value lowered      |\n| a lesion             | a closed door                                                  |\n\nOne layer, from dolls to dolls:\n\n```\nflowchart LR\n    A[\"input value<br/>= a crowd of dolls\"] --> B[\"weight lines<br/>each crossing adds w\"]\n    B --> C[\"the sum<br/>= a light level or height\"]\n    C --> D[\"staircase of gates<br/>= the activation\"]\n    D --> E[\"next layer's dolls\"]\n```\n\n Loading\n\nThe engine has sharp edges, and the compiler works around them:\n\n- A floor mover ignores a second request while it is still moving.\n- A teleport cancels lines a doll crossed earlier in the same tic.\n- Things far from a BSP node can land in the wrong room, so every map fits in 32,000 units.\n\n`doomformer facts` checks these in about 10 s. [Engine facts](https://github.com/mottopanikeiku/doomformer/blob/main/docs/HOW_IT_WORKS.md#engine-facts) · [Engine features it needs](https://github.com/mottopanikeiku/doomformer/blob/main/docs/HOW_IT_WORKS.md#engine-features-it-needs) · [Other ports](https://github.com/mottopanikeiku/doomformer/blob/main/docs/engine_limits.md#other-ports)\n\nComputers in DOOM maps are not new. [counter.wad](https://www.wad-archive.com/wad/8d0de31d8b392fc2d7fd817e933b3cf43bca799a) counts with voodoo dolls, [conway.wad](https://github.com/pwiecz/conway.wad) runs Game of Life, and [Danny Spencer's calculator](https://github.com/nukep/doom-calculator) adds numbers. New here: a compiler for neural networks, and an exact check on every value. [Related work](https://github.com/mottopanikeiku/doomformer/blob/main/docs/related_work.md)\n\n## What is checked\n\n[![Pipeline: your network becomes integers and a DOOM map, ViZDoom runs it and Python reads the values back (light levels and plane heights). A NumPy integer reference, which never sees the map, computes the same values. Every value is compared with tolerance 0: EXACT or MismatchError.](https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/pipeline.png)](https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/pipeline.png)\n\nEvery run compares each value the map exposes with NumPy. That proves the inputs that ran, nothing more. So the repo also attacks its own check:\n\n| attack                                                    | result                                              |\n| --------------------------------------------------------- | --------------------------------------------------- |\n| **Tamper** with one weight line                           | the check fails on exactly the inputs that cross it |\n| **Fuzz** 20,000 random nets at the range limits           | 0 mismatches; CI fuzzes a fresh seed on every push  |\n| **Mutate** one line of a map, 1,004 times                 | 297 caught; no survivor is proven harmless          |\n| **Extract** the weights back out of the map, without DOOM | equal to the source net                             |\n| **Guard** every readout page with a poison value          | a page that never runs cannot pass old values       |\n\nThe MNIST map exposes 248 values. It does not expose its 903 staircase counts and 1,351 gate comparisons. Those are checked only through the sums they feed. Fuzzing and tests found four bugs in the compiler. All are fixed. [Verification](https://github.com/mottopanikeiku/doomformer/blob/main/docs/verification.md)\n\n**Who computes what**\n\n| run                                           | Python                                                     | voodoo dolls                                     |\n| --------------------------------------------- | ---------------------------------------------------------- | ------------------------------------------------ |\n| `mnist`, `df.compile`                         | writes the inputs, waits, reads                            | every sum, activation, comparison and the choice |\n| `demo`, `ask` (tile maps)                     | writes tokens, copies values between maps, samples letters | every sum and activation                         |\n| `draw`, `--loop`, the marine's brain, the fly | only advances the clock and reads                          | everything, including the choice                 |\n| `machine`                                     | loads the program, then advances the clock and reads       | program counter and registers                    |\n| `museum`, played in GZDoom                    | nothing                                                    | every sum, comparison and the choice             |\n\nACS level scripts move gates, rewind the dolls, sense the world and copy results out. Two do more. `df.Agent` takes an argmax in ACS. `--opt 3` copies each layer's values into the next layer with a script. [Per demo](https://github.com/mottopanikeiku/doomformer/blob/main/docs/HOW_IT_WORKS.md#who-does-what-per-demo)\n\nThe maps need ZDoom (UDMF and ACS). This repo runs [ViZDoom](https://github.com/Farama-Foundation/ViZDoom) 1.3.2 with Freedoom assets.\n\n## Commands\n\n| Command                                           | What DOOM does                             | Time         | Skill level          |\n| ------------------------------------------------- | ------------------------------------------ | ------------ | -------------------- |\n| `doomformer hello`                                | a small MLP, 5 random inputs               | 2 s          | I'm too young to die |\n| `doomformer draw --digit 7`                       | the marine walks a 7, the level reads it   | 15 s         | Hey, not too rough   |\n| `doomformer museum build`                         | a playable map that reads a digit          | 1 s          | Hey, not too rough   |\n| `doomformer mnist`                                | reads 4 test digits, or your own image     | 1.5 to 3 min | Hurt me plenty       |\n| `doomformer demo`                                 | a transformer writes a level name          | 15 to 60 s   | Hurt me plenty       |\n| `doomformer machine subleq all`                   | a tiny computer runs three programs        | about 5 min  | Ultra-Violence       |\n| `doomformer learn digits --classes 4 --steps 300` | a blank brain learns digits inside the map | about 5 min  | Ultra-Violence       |\n| `doomformer ask \"what does iddqd do\"`             | answers from 189 DOOM facts                | about 11 min | Ultra-Violence       |\n| `doomformer demo --nightmare`                     | the 2-layer model, 106 tile maps           | 3.5 to 7 min | Nightmare!           |\n\nTimes are from a 16-core arm64 Linux machine. [Every command](https://github.com/mottopanikeiku/doomformer/blob/main/docs/commands.md)\n\nSome outputs are picked. DEMON CANYON, the name `--nightmare` writes, is one hand-picked sample. `ask` gets 94.7 % of its training questions right, and 35.4 % of new wordings.\n\n## Bigger experiments\n\n[![His brain is the level: the marine fights a demon while 1,345 dots on the right, voodoo dolls of him, run his policy transformer](https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/hero.gif)](https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/hero.gif)\n\n**His brain is the level.** The level senses the nearest demon. 1,345 voodoo dolls of the marine run his brain and pick an action. The level turns him and fires. Python only steps the clock and reads. 50 of 50 decisions are exact. [Film](https://mottopanikeiku.github.io/doomformer/#brain) · [Code](https://github.com/mottopanikeiku/doomformer/blob/main/demos/brainlevel.py)\n\nWarning\n\nHe is not playable. One decision takes 22 s of game time, and the demons are frozen while he thinks. With the demons awake (`--live`), he dies in 5.5 s without a kill. [Live demons](https://github.com/mottopanikeiku/doomformer/blob/main/docs/DEMOS.md#live-demons-what-the-latency-costs-him)\n\n| run it from a clone                             | what you see                                          |\n| ----------------------------------------------- | ----------------------------------------------------- |\n| `python -m demos.brainlevel`                    | his brain is the level                                |\n| `python -m demos.brainlevel --live`             | the same brain against awake demons                   |\n| `python -m demos.brainlevel --lesion-when near` | the level closes neuron doors when a demon gets close |\n| `python -m demos.aimlearn`                      | a perceptron learns to aim inside one game            |\n| `python -m demos.flyloop`                       | a fruit-fly circuit drives the marine                 |\n| `python -m demos.lobotomy`                      | lesions that turn him into a pacifist                 |\n\n[All demos, numbers and picked seeds](https://github.com/mottopanikeiku/doomformer/blob/main/docs/DEMOS.md)\n\n## Build your own\n\nCompile a network into a map. Let its outputs open doors, flash lights or shove the marine. This runs as pasted:\n\n```python\nimport numpy as np\nimport doomformer as df\n\n# 2 inputs -> [a AND b, a OR b] -> 2 outputs, all integers\nnet = df.MLP(\n    weights=[np.array([[1, 1], [1, 1]]), np.array([[1, 0], [0, 1]])],\n    biases=[np.array([-1, 0]), np.array([0, 0])],\n    thresholds=[np.array([1]), np.array([1])],\n    signed_input=False,\n)\nwith df.compile(net) as brain:\n    for x in ([0, 0], [1, 0], [1, 1]):\n        # computed by voodoo dolls; raises df.MismatchError on any difference from net.reference\n        print(x, \"->\", brain(np.array(x)).tolist())\n    brain.record([np.array([0, 1]), np.array([1, 1])], \"dolls.gif\")   # film the dolls doing it\n```\n\n`df.MLP.from_torch` converts a PyTorch model ([example 02](https://github.com/mottopanikeiku/doomformer/blob/main/examples/02_pytorch_to_doom.py)). The `world` and `actions` hooks wire outputs to doors, lights and thrusts ([example 03](https://github.com/mottopanikeiku/doomformer/blob/main/examples/03_brain_opens_doors.py)). [Guide](https://github.com/mottopanikeiku/doomformer/blob/main/docs/BUILD_YOUR_OWN.md) · [12 examples](https://github.com/mottopanikeiku/doomformer/blob/main/examples) · [Show and tell](https://github.com/mottopanikeiku/doomformer/issues/new/choose)\n\n## Many games at once\n\nOne map runs in one game, on one core. `df.run_many` spreads inputs over many games, or over a Ray cluster. A network can also be split into tile maps, one per layer. Then Python copies values between them.\n\n| run                  | digits | right | exact  | time   |\n| -------------------- | ------ | ----- | ------ | ------ |\n| one map, 14 games    | 1,000  | 966   | 1,000  | 2 h    |\n| 4 tile maps, 6 games | 10,000 | 9,716 | 10,000 | 23 min |\n\n```shell\ndoomformer mnist --tiles --all --workers 6         # all 10,000 digits as tile maps, about 23 min\npip install \"doomformer[ray]\"\nray start --head                  # other machines: ray start --address=HEAD:6379\ndoomformer mnist --all --ray --record mnist.json   # all 10,000 digits, one map each, on a cluster\n```\n\nBudget one core and 1.3 GB of RAM per game. [Scaling](https://github.com/mottopanikeiku/doomformer/blob/main/docs/scaling.md#scaling-out-many-games-many-machines)\n\n## More\n\n| what                                                      | try                                 | read                                                                                           |\n| --------------------------------------------------------- | ----------------------------------- | ---------------------------------------------------------------------------------------------- |\n| Faster schedules: MNIST in one map from 5,696 to 272 tics | `--opt 3`                           | [scheduling](https://github.com/mottopanikeiku/doomformer/blob/main/docs/scheduling.md)       |\n| A counter machine: 7 × 9 = 63 in 464 checked steps        | `doomformer machine multiply 7 9`   | [machine](https://github.com/mottopanikeiku/doomformer/blob/main/docs/machine.md)             |\n| A SUBLEQ machine with self-modifying code                 | `doomformer machine subleq all`     | [machine](https://github.com/mottopanikeiku/doomformer/blob/main/docs/machine.md)             |\n| A blank brain learns digits in the map: 71 % held-out     | `doomformer learn digits`           | [learning](https://github.com/mottopanikeiku/doomformer/blob/main/docs/learning.md)           |\n| PyTorch import with BatchNorm, pooling and QAT            | `MLP.from_torch`                    | [interop](https://github.com/mottopanikeiku/doomformer/blob/main/docs/interop.md)             |\n| A transformer that learned induction, exact in DOOM       | `python -m demos.induction`         | [induction](https://github.com/mottopanikeiku/doomformer/blob/main/models/induction/EVAL.md)  |\n| Patching, lesions and steering, checked in DOOM           | `intref.forward(interventions=...)` | [interventions](https://github.com/mottopanikeiku/doomformer/blob/main/docs/interventions.md) |\n| Speed per pass and throughput                             | `doomformer bench`                  | [scaling](https://github.com/mottopanikeiku/doomformer/blob/main/docs/scaling.md)             |\n\n## Limits\n\nImportant\n\n- **Slow.** A small MLP runs about 23,000 times slower than NumPy. Most of the time goes to idle conveyor belts. [Speed](https://github.com/mottopanikeiku/doomformer/blob/main/docs/HOW_IT_WORKS.md#speed)\n- **Only the runs are checked.** Inputs that never ran are not covered. [Not covered](https://github.com/mottopanikeiku/doomformer/blob/main/docs/verification.md#not-covered)\n- **Integer models.** Attention is integer attention. No model has LayerNorm.\n- **ViZDoom first.** Other DOOM engines ran only small maps.\n- **No reinforcement learning.** The marine copies a scripted aimbot.\n- **Finite machines.** Memory is bounded. Nothing here claims DOOM is Turing complete.\n- **Picked samples.** Showcased seeds and names are picked. [The list](https://github.com/mottopanikeiku/doomformer/blob/main/docs/DEMOS.md#seeds-and-selection)\n\n## What's in the box\n\n| Path                                                                                   | What it holds                                                                                                                                                     |\n| -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| [`doomformer/`](https://github.com/mottopanikeiku/doomformer/blob/main/doomformer)    | the toolkit: map compiler, DOOM runtime, exact checks, CLI                                                                                                        |\n| [`demos/`](https://github.com/mottopanikeiku/doomformer/blob/main/demos)              | research code: the marine's brain, the level generator, the fly circuit, the learning arena                                                                       |\n| [`training/`](https://github.com/mottopanikeiku/doomformer/blob/main/training)        | training scripts for every model, with the data and sources                                                                                                       |\n| [`models/`](https://github.com/mottopanikeiku/doomformer/blob/main/models)            | every trained model with its training log and evaluation                                                                                                          |\n| [`examples/`](https://github.com/mottopanikeiku/doomformer/blob/main/examples)        | twelve one-file examples, most under 15 s                                                                                                                         |\n| [`tests/`](https://github.com/mottopanikeiku/doomformer/blob/main/tests)              | 496 tests; CI runs them against real headless DOOM on Linux and macOS                                                                                             |\n| [`docs/`](https://github.com/mottopanikeiku/doomformer/blob/main/docs/README.md)      | how it works, every demo with its numbers, the engine facts, the guide, [every command](https://github.com/mottopanikeiku/doomformer/blob/main/docs/commands.md) |\n| [`CHANGELOG.md`](https://github.com/mottopanikeiku/doomformer/blob/main/CHANGELOG.md) | what each release added                                                                                                                                           |\n\n## Licensing\n\nCode and docs: [MIT](https://github.com/mottopanikeiku/doomformer/blob/main/LICENSE). Data keeps its own licence ([THIRD\\_PARTY.md](https://github.com/mottopanikeiku/doomformer/blob/main/THIRD_PARTY.md)). The level-name lists come from the Doom Wiki (CC BY-SA 4.0) and id Software's source (GPL-2.0). The 100 sample MNIST digits are CC BY-SA 3.0. The fruit-fly circuits in `models/fly` come from the FlyWire connectome (CC BY-NC 4.0, non-commercial). Freedoom graphics are BSD-licensed. DOOM is a trademark of id Software / ZeniMax. This project is not affiliated with them.\n",
  "authors": [
    "falperc"
  ],
  "captured_at": "2026-10-30T13:27:01.845275939+00:00",
  "category": "news",
  "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/banner_wide.png\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/banner_wide.png\" alt=\"DOOMFORMER: the marine fights a horde of demons under a hellish sky\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<p><strong>Neural networks computed by voodoo dolls inside DOOM maps.</strong><br />\nEvery value is read back and checked against NumPy. Tolerance 0.</p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/actions/workflows/tests.yml\"><picture class=\"article-picture article-badge\" style=\"--image-width:160px;--image-ratio:160 / 24\"><img src=\"https://github.com/mottopanikeiku/doomformer/actions/workflows/tests.yml/badge.svg\" width=\"160\" height=\"24\" alt=\"tests\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a> <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/releases\"><picture class=\"article-picture article-badge\" style=\"--image-width:160px;--image-ratio:160 / 24\"><img src=\"https://camo.githubusercontent.com/bd90ae1758c512eefd27c9166c2687910317d20c7e48a052a3b85b95d1b3918e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6d6f74746f70616e696b65696b752f646f6f6d666f726d65723f636f6c6f723d386230303030\" width=\"160\" height=\"24\" alt=\"release\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a> <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://camo.githubusercontent.com/96abf9b704f80578ea56dd10cab0d911c56d46dbec347f431ece9cf60ac175ad/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f707974686f6e2d332e31312532422d626c7565\"><picture class=\"article-picture article-badge\" style=\"--image-width:160px;--image-ratio:160 / 24\"><img src=\"https://camo.githubusercontent.com/96abf9b704f80578ea56dd10cab0d911c56d46dbec347f431ece9cf60ac175ad/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f707974686f6e2d332e31312532422d626c7565\" width=\"160\" height=\"24\" alt=\"Python 3.11+\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a> <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/LICENSE\"><picture class=\"article-picture article-badge\" style=\"--image-width:160px;--image-ratio:160 / 24\"><img src=\"https://camo.githubusercontent.com/b8cadaa967891081f8f165695470689986c028821dd8a040132f6e661795dc0d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c7565\" width=\"160\" height=\"24\" alt=\"MIT\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a> <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://colab.research.google.com/github/mottopanikeiku/doomformer/blob/main/examples/doomformer_colab.ipynb\"><picture class=\"article-picture article-badge\" style=\"--image-width:160px;--image-ratio:160 / 24\"><img src=\"https://camo.githubusercontent.com/eff96fda6b2e0fff8cdf2978f89d61aa434bb98c00453ae23dd0aab8d1451633/68747470733a2f2f636f6c61622e72657365617263682e676f6f676c652e636f6d2f6173736574732f636f6c61622d62616467652e737667\" width=\"160\" height=\"24\" alt=\"Open in Colab\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer#quick-start\">Quick start</a> · <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer#walk-a-digit-doom-reads-it\">Walk a digit</a> · <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer#the-museum-rewire-one-connection\">The museum</a> · <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer#how-it-works\">How it works</a> · <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer#what-is-checked\">What is checked</a> · <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mottopanikeiku.github.io/doomformer/\">Films</a> · <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/README.md\">Docs</a></p>\n<table>\n<thead>\n<tr>\n<th><strong>10,000 / 10,000</strong></th>\n<th><strong>1,355</strong></th>\n<th><strong>0</strong></th>\n<th><strong>4</strong></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>MNIST test digits exact</td>\n<td>voodoo dolls in one MNIST map</td>\n<td>mismatches in 20,000 fuzzed nets</td>\n<td>other DOOM engines run the museum exactly</td>\n</tr>\n</tbody>\n</table>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/ladder.png\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/ladder.png\" alt=\"A number is a crowd of voodoo dolls. A weight is a line on the floor. A sum is a light level or a height. An activation is a staircase. Attention is a ceiling. Every value is read back and compared with NumPy: tolerance 0.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<h2>Quick start</h2>\n<pre><code class=\"language-shell\"><span class=\"code-snippet\" data-language=\"Shell\"><span class=\"syntax-source syntax-shell syntax-bash\"><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">pip</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> install git+https://github.com/mottopanikeiku/doomformer   <span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> Python 3.11+, Linux or macOS</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span></span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">doomformer</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> hello             <span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> 2 s: a small MLP, every value checked</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span></span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">doomformer</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> draw<span class=\"syntax-variable syntax-parameter syntax-option syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-parameter syntax-shell\"> --</span>digit</span> 7    <span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> 15 s: the marine walks a 7 and the level reads it</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span></span></span></span></code></pre>\n<p><code>doomformer doctor</code> checks your setup. It builds ACC, the ACS compiler, if it is missing. That needs git, cmake and a C compiler. On Fedora: <code>sudo dnf install git cmake gcc gcc-c++ make</code>.</p>\n<p>Tip</p>\n<p>No install needed for the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://colab.research.google.com/github/mottopanikeiku/doomformer/blob/main/examples/doomformer_colab.ipynb\">Colab notebook</a>. Draw a digit in your browser and DOOM reads it.</p>\n<h2>Walk a digit, DOOM reads it</h2>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/drawpad.gif\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/drawpad.gif\" alt=\"DrawPad: the marine walks a 7 across a 28x28 floor canvas, presses READ, and the winning voodoo doll lights a 7 on a 7-segment display\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<p>The marine holds FIRE and inks the floor. Then he presses READ.</p>\n<p>1,355 voodoo dolls in the same map run an MNIST network. The winning digit's doll crosses a line. That line lights the digit on the display.</p>\n<pre><code><span class=\"code-snippet\">          ▄▄▄▄▄▄▄▄▄▄▄▄▄▄\n       ▄████████████████\n       ████▀▀     ▀████▀\n       ▀▀▀        ▄███▀\n                  ████\n                  ███\n                  ███\n                  ███\n                 ████\n                 ███▀\n                 ████\n                 ▀███\n\nDOOM reads: 7  (right)   -- the winner&#39;s doll lit it on the 7-segment display\nEXACT: all 248 values DOOM computed [...] equal the NumPy integer reference (tolerance 0)\nREAD pass: 273 game tics = 8 s of real-time DOOM at 35 tics/s, 3 s wall [...]\n</span></code></pre>\n<p>Python reads back 248 values and checks every one. With <code>--digit</code>, Python presses the keys for you. Without it, you walk and draw yourself. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/commands.md#doomformer-draw---digit-7\">Full output</a></p>\n<p>Note</p>\n<p>EXACT means DOOM got the same numbers as the integer network. It does not mean the digit is right.</p>\n<table>\n<thead>\n<tr>\n<th>run</th>\n<th>right</th>\n<th>exact</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>first 100 MNIST test digits</td>\n<td>99</td>\n<td>100</td>\n</tr>\n<tr>\n<td>1,000 sampled test digits, one map each</td>\n<td>966</td>\n<td>1,000</td>\n</tr>\n<tr>\n<td>all 10,000 test digits, tile maps</td>\n<td>9,716 (97.16 %)</td>\n<td>10,000</td>\n</tr>\n</tbody>\n</table>\n<p>The float model scores 97.58 %. The network also trained on the strokes the scripted marine walks. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/drawpad.md\">Details</a> · <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mottopanikeiku.github.io/doomformer/#drawpad\">Film</a></p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/mnist.png\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/mnist.png\" alt=\"eight MNIST test digits and what DOOM read: 7 2 1 0 4 9 6 3, all exact\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<h2>The museum: rewire one connection</h2>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/releases/download/v0.7.1/museum_mutate.png\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://github.com/mottopanikeiku/doomformer/releases/download/v0.7.1/museum_mutate.png\" alt=\"Two views of one doll lane. Before MUTATE, DOOM reads 7 and the doll has passed its gate. After MUTATE, DOOM reads 1 and the same voodoo doll stands at its gate.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<p>Tip</p>\n<p><strong>Play it without Python.</strong> Download <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/releases/download/v0.7.1/museum.wad\">museum.wad</a> (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/releases/download/v0.7.1/museum_SHA256SUMS.txt\">sha256</a>) and the free <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://freedoom.github.io/download.html\">Freedoom</a> IWAD. Then run <code>gzdoom -iwad freedoom2.wad -file museum.wad</code>.</p>\n<p>Step on seven floor pads to light a digit. Press READ. 136 voodoo dolls run a tiny network and light the answer.</p>\n<p>Press MUTATE and the level rewires one connection while it runs. The same 7 now reads as 1. You can watch it happen: one doll stops at its gate.</p>\n<pre><code><span class=\"code-snippet\" data-language=\"Shell\"><span class=\"syntax-source syntax-shell syntax-bash\"><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">$</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> doomformer museum verify</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">7</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\">                        pads abc     w_7a +1  DOOM reads 7  scores <span class=\"syntax-keyword syntax-control syntax-regexp syntax-set syntax-begin syntax-shell\">[</span>4, 6, 3, 5, 4, 3, 2, 7, 3, 4<span class=\"syntax-keyword syntax-control syntax-regexp syntax-set syntax-end syntax-shell\">]</span>  EXACT (148 values</span><span class=\"syntax-keyword syntax-operator syntax-logical syntax-continue syntax-shell\">;</span> <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">744</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> tics</span><span class=\"syntax-keyword syntax-operator syntax-logical syntax-continue syntax-shell\">;</span> <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">[...]</span></span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">)</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">7</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> after MUTATE           pads abc     w_7a<span class=\"syntax-variable syntax-parameter syntax-option syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-parameter syntax-shell\"> -</span>1</span>  DOOM reads 1  scores <span class=\"syntax-keyword syntax-control syntax-regexp syntax-set syntax-begin syntax-shell\">[</span>4, 6, 3, 5, 4, 3, 2, 5, 3, 4<span class=\"syntax-keyword syntax-control syntax-regexp syntax-set syntax-end syntax-shell\">]</span>  EXACT (148 values</span><span class=\"syntax-keyword syntax-operator syntax-logical syntax-continue syntax-shell\">;</span> <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">744</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> tics</span><span class=\"syntax-keyword syntax-operator syntax-logical syntax-continue syntax-shell\">;</span> <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">[...]</span></span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">)</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">7</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> after RESTORE          pads abc     w_7a +1  DOOM reads 7  scores <span class=\"syntax-keyword syntax-control syntax-regexp syntax-set syntax-begin syntax-shell\">[</span>4, 6, 3, 5, 4, 3, 2, 7, 3, 4<span class=\"syntax-keyword syntax-control syntax-regexp syntax-set syntax-end syntax-shell\">]</span>  EXACT (148 values</span><span class=\"syntax-keyword syntax-operator syntax-logical syntax-continue syntax-shell\">;</span> <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">744</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> tics</span><span class=\"syntax-keyword syntax-operator syntax-logical syntax-continue syntax-shell\">;</span> <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">[...]</span></span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">)</span>\n</span></span></code></pre>\n<p>A self-test version runs exactly in GZDoom, LZDoom, UZDoom and ZDoom 2.8.1. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/museum.md\">Details</a></p>\n<h2>How it works</h2>\n<p>Every part of a network becomes a part of the map:</p>\n<table>\n<thead>\n<tr>\n<th>in a neural network</th>\n<th>in the DOOM map</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>a value of 5</td>\n<td>5 voodoo dolls</td>\n</tr>\n<tr>\n<td>a weight</td>\n<td>a line on the floor; each doll that crosses it adds the weight</td>\n</tr>\n<tr>\n<td>a sum</td>\n<td>a sector's light level or floor height</td>\n</tr>\n<tr>\n<td>an activation (ReLU)</td>\n<td>a staircase of gates the dolls must climb</td>\n</tr>\n<tr>\n<td>attention</td>\n<td>dolls squeezing under ceilings that another value lowered</td>\n</tr>\n<tr>\n<td>a lesion</td>\n<td>a closed door</td>\n</tr>\n</tbody>\n</table>\n<p>One layer, from dolls to dolls:</p>\n<pre><code><span class=\"code-snippet\">flowchart LR\n    A[&quot;input value&lt;br/&gt;= a crowd of dolls&quot;] --&gt; B[&quot;weight lines&lt;br/&gt;each crossing adds w&quot;]\n    B --&gt; C[&quot;the sum&lt;br/&gt;= a light level or height&quot;]\n    C --&gt; D[&quot;staircase of gates&lt;br/&gt;= the activation&quot;]\n    D --&gt; E[&quot;next layer&#39;s dolls&quot;]\n</span></code></pre>\n<p>Loading</p>\n<p>The engine has sharp edges, and the compiler works around them:</p>\n<ul>\n<li>A floor mover ignores a second request while it is still moving.</li>\n<li>A teleport cancels lines a doll crossed earlier in the same tic.</li>\n<li>Things far from a BSP node can land in the wrong room, so every map fits in 32,000 units.</li>\n</ul>\n<p><code>doomformer facts</code> checks these in about 10 s. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/HOW_IT_WORKS.md#engine-facts\">Engine facts</a> · <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/HOW_IT_WORKS.md#engine-features-it-needs\">Engine features it needs</a> · <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/engine_limits.md#other-ports\">Other ports</a></p>\n<p>Computers in DOOM maps are not new. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.wad-archive.com/wad/8d0de31d8b392fc2d7fd817e933b3cf43bca799a\">counter.wad</a> counts with voodoo dolls, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/pwiecz/conway.wad\">conway.wad</a> runs Game of Life, and <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/nukep/doom-calculator\">Danny Spencer's calculator</a> adds numbers. New here: a compiler for neural networks, and an exact check on every value. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/related_work.md\">Related work</a></p>\n<h2>What is checked</h2>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/pipeline.png\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/pipeline.png\" alt=\"Pipeline: your network becomes integers and a DOOM map, ViZDoom runs it and Python reads the values back (light levels and plane heights). A NumPy integer reference, which never sees the map, computes the same values. Every value is compared with tolerance 0: EXACT or MismatchError.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<p>Every run compares each value the map exposes with NumPy. That proves the inputs that ran, nothing more. So the repo also attacks its own check:</p>\n<table>\n<thead>\n<tr>\n<th>attack</th>\n<th>result</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>Tamper</strong> with one weight line</td>\n<td>the check fails on exactly the inputs that cross it</td>\n</tr>\n<tr>\n<td><strong>Fuzz</strong> 20,000 random nets at the range limits</td>\n<td>0 mismatches; CI fuzzes a fresh seed on every push</td>\n</tr>\n<tr>\n<td><strong>Mutate</strong> one line of a map, 1,004 times</td>\n<td>297 caught; no survivor is proven harmless</td>\n</tr>\n<tr>\n<td><strong>Extract</strong> the weights back out of the map, without DOOM</td>\n<td>equal to the source net</td>\n</tr>\n<tr>\n<td><strong>Guard</strong> every readout page with a poison value</td>\n<td>a page that never runs cannot pass old values</td>\n</tr>\n</tbody>\n</table>\n<p>The MNIST map exposes 248 values. It does not expose its 903 staircase counts and 1,351 gate comparisons. Those are checked only through the sums they feed. Fuzzing and tests found four bugs in the compiler. All are fixed. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/verification.md\">Verification</a></p>\n<p><strong>Who computes what</strong></p>\n<table>\n<thead>\n<tr>\n<th>run</th>\n<th>Python</th>\n<th>voodoo dolls</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>mnist</code>, <code>df.compile</code></td>\n<td>writes the inputs, waits, reads</td>\n<td>every sum, activation, comparison and the choice</td>\n</tr>\n<tr>\n<td><code>demo</code>, <code>ask</code> (tile maps)</td>\n<td>writes tokens, copies values between maps, samples letters</td>\n<td>every sum and activation</td>\n</tr>\n<tr>\n<td><code>draw</code>, <code>--loop</code>, the marine's brain, the fly</td>\n<td>only advances the clock and reads</td>\n<td>everything, including the choice</td>\n</tr>\n<tr>\n<td><code>machine</code></td>\n<td>loads the program, then advances the clock and reads</td>\n<td>program counter and registers</td>\n</tr>\n<tr>\n<td><code>museum</code>, played in GZDoom</td>\n<td>nothing</td>\n<td>every sum, comparison and the choice</td>\n</tr>\n</tbody>\n</table>\n<p>ACS level scripts move gates, rewind the dolls, sense the world and copy results out. Two do more. <code>df.Agent</code> takes an argmax in ACS. <code>--opt 3</code> copies each layer's values into the next layer with a script. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/HOW_IT_WORKS.md#who-does-what-per-demo\">Per demo</a></p>\n<p>The maps need ZDoom (UDMF and ACS). This repo runs <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/Farama-Foundation/ViZDoom\">ViZDoom</a> 1.3.2 with Freedoom assets.</p>\n<h2>Commands</h2>\n<table>\n<thead>\n<tr>\n<th>Command</th>\n<th>What DOOM does</th>\n<th>Time</th>\n<th>Skill level</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>doomformer hello</code></td>\n<td>a small MLP, 5 random inputs</td>\n<td>2 s</td>\n<td>I'm too young to die</td>\n</tr>\n<tr>\n<td><code>doomformer draw --digit 7</code></td>\n<td>the marine walks a 7, the level reads it</td>\n<td>15 s</td>\n<td>Hey, not too rough</td>\n</tr>\n<tr>\n<td><code>doomformer museum build</code></td>\n<td>a playable map that reads a digit</td>\n<td>1 s</td>\n<td>Hey, not too rough</td>\n</tr>\n<tr>\n<td><code>doomformer mnist</code></td>\n<td>reads 4 test digits, or your own image</td>\n<td>1.5 to 3 min</td>\n<td>Hurt me plenty</td>\n</tr>\n<tr>\n<td><code>doomformer demo</code></td>\n<td>a transformer writes a level name</td>\n<td>15 to 60 s</td>\n<td>Hurt me plenty</td>\n</tr>\n<tr>\n<td><code>doomformer machine subleq all</code></td>\n<td>a tiny computer runs three programs</td>\n<td>about 5 min</td>\n<td>Ultra-Violence</td>\n</tr>\n<tr>\n<td><code>doomformer learn digits --classes 4 --steps 300</code></td>\n<td>a blank brain learns digits inside the map</td>\n<td>about 5 min</td>\n<td>Ultra-Violence</td>\n</tr>\n<tr>\n<td><code>doomformer ask &quot;what does iddqd do&quot;</code></td>\n<td>answers from 189 DOOM facts</td>\n<td>about 11 min</td>\n<td>Ultra-Violence</td>\n</tr>\n<tr>\n<td><code>doomformer demo --nightmare</code></td>\n<td>the 2-layer model, 106 tile maps</td>\n<td>3.5 to 7 min</td>\n<td>Nightmare!</td>\n</tr>\n</tbody>\n</table>\n<p>Times are from a 16-core arm64 Linux machine. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/commands.md\">Every command</a></p>\n<p>Some outputs are picked. DEMON CANYON, the name <code>--nightmare</code> writes, is one hand-picked sample. <code>ask</code> gets 94.7 % of its training questions right, and 35.4 % of new wordings.</p>\n<h2>Bigger experiments</h2>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/hero.gif\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/hero.gif\" alt=\"His brain is the level: the marine fights a demon while 1,345 dots on the right, voodoo dolls of him, run his policy transformer\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<p><strong>His brain is the level.</strong> The level senses the nearest demon. 1,345 voodoo dolls of the marine run his brain and pick an action. The level turns him and fires. Python only steps the clock and reads. 50 of 50 decisions are exact. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mottopanikeiku.github.io/doomformer/#brain\">Film</a> · <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/demos/brainlevel.py\">Code</a></p>\n<p>Warning</p>\n<p>He is not playable. One decision takes 22 s of game time, and the demons are frozen while he thinks. With the demons awake (<code>--live</code>), he dies in 5.5 s without a kill. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/DEMOS.md#live-demons-what-the-latency-costs-him\">Live demons</a></p>\n<table>\n<thead>\n<tr>\n<th>run it from a clone</th>\n<th>what you see</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>python -m demos.brainlevel</code></td>\n<td>his brain is the level</td>\n</tr>\n<tr>\n<td><code>python -m demos.brainlevel --live</code></td>\n<td>the same brain against awake demons</td>\n</tr>\n<tr>\n<td><code>python -m demos.brainlevel --lesion-when near</code></td>\n<td>the level closes neuron doors when a demon gets close</td>\n</tr>\n<tr>\n<td><code>python -m demos.aimlearn</code></td>\n<td>a perceptron learns to aim inside one game</td>\n</tr>\n<tr>\n<td><code>python -m demos.flyloop</code></td>\n<td>a fruit-fly circuit drives the marine</td>\n</tr>\n<tr>\n<td><code>python -m demos.lobotomy</code></td>\n<td>lesions that turn him into a pacifist</td>\n</tr>\n</tbody>\n</table>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/DEMOS.md\">All demos, numbers and picked seeds</a></p>\n<h2>Build your own</h2>\n<p>Compile a network into a map. Let its outputs open doors, flash lights or shove the marine. This runs as pasted:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">numpy</span></span> <span class=\"syntax-keyword syntax-control syntax-import syntax-as syntax-python\">as</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">np</span></span></span>\n<span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">doomformer</span></span> <span class=\"syntax-keyword syntax-control syntax-import syntax-as syntax-python\">as</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">df</span></span></span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> 2 inputs -&gt; [a AND b, a OR b] -&gt; 2 outputs, all integers\n</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">net</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">df</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">MLP</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\">\n    <span class=\"syntax-variable syntax-parameter syntax-python\">weights</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">np</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">array</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">np</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">array</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">biases</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">np</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">array</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">-</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">np</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">array</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">thresholds</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">np</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">array</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">np</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">array</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">signed_input</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-constant syntax-language syntax-python\">False</span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-statement syntax-with syntax-python\"><span class=\"syntax-keyword syntax-control syntax-flow syntax-with syntax-python\">with</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">df</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">compile</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">net</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span> <span class=\"syntax-meta syntax-statement syntax-with syntax-python\"><span class=\"syntax-keyword syntax-control syntax-flow syntax-with syntax-as syntax-python\">as</span></span></span><span class=\"syntax-meta syntax-statement syntax-with syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">brain</span><span class=\"syntax-punctuation syntax-section syntax-block syntax-with syntax-python\">:</span></span>\n    <span class=\"syntax-meta syntax-statement syntax-for syntax-python\"><span class=\"syntax-keyword syntax-control syntax-flow syntax-for syntax-python\">for</span> <span class=\"syntax-meta syntax-generic-name syntax-python\">x</span> <span class=\"syntax-meta syntax-statement syntax-for syntax-python\"><span class=\"syntax-keyword syntax-control syntax-flow syntax-for syntax-in syntax-python\">in</span></span></span><span class=\"syntax-meta syntax-statement syntax-for syntax-python\"> <span class=\"syntax-meta syntax-group syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span><span class=\"syntax-punctuation syntax-separator syntax-tuple syntax-python\">,</span> <span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span><span class=\"syntax-punctuation syntax-separator syntax-tuple syntax-python\">,</span> <span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-section syntax-block syntax-for syntax-python\">:</span></span>\n        <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> computed by voodoo dolls; raises df.MismatchError on any difference from net.reference\n</span>        <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">print</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">x</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">-&gt;<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">brain</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">np</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">array</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">x</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">tolist</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n    <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">brain</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">record</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">np</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">array</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">np</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">array</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">dolls.gif<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>   <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> film the dolls doing it\n</span></span></span></code></pre>\n<p><code>df.MLP.from_torch</code> converts a PyTorch model (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/examples/02_pytorch_to_doom.py\">example 02</a>). The <code>world</code> and <code>actions</code> hooks wire outputs to doors, lights and thrusts (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/examples/03_brain_opens_doors.py\">example 03</a>). <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/BUILD_YOUR_OWN.md\">Guide</a> · <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/examples\">12 examples</a> · <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/issues/new/choose\">Show and tell</a></p>\n<h2>Many games at once</h2>\n<p>One map runs in one game, on one core. <code>df.run_many</code> spreads inputs over many games, or over a Ray cluster. A network can also be split into tile maps, one per layer. Then Python copies values between them.</p>\n<table>\n<thead>\n<tr>\n<th>run</th>\n<th>digits</th>\n<th>right</th>\n<th>exact</th>\n<th>time</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>one map, 14 games</td>\n<td>1,000</td>\n<td>966</td>\n<td>1,000</td>\n<td>2 h</td>\n</tr>\n<tr>\n<td>4 tile maps, 6 games</td>\n<td>10,000</td>\n<td>9,716</td>\n<td>10,000</td>\n<td>23 min</td>\n</tr>\n</tbody>\n</table>\n<pre><code class=\"language-shell\"><span class=\"code-snippet\" data-language=\"Shell\"><span class=\"syntax-source syntax-shell syntax-bash\"><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">doomformer</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> mnist<span class=\"syntax-variable syntax-parameter syntax-option syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-parameter syntax-shell\"> --</span>tiles</span><span class=\"syntax-variable syntax-parameter syntax-option syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-parameter syntax-shell\"> --</span>all</span><span class=\"syntax-variable syntax-parameter syntax-option syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-parameter syntax-shell\"> --</span>workers</span> 6         <span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> all 10,000 digits as tile maps, about 23 min</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span></span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">pip</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> install <span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>doomformer[ray]<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span></span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">ray</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> start<span class=\"syntax-variable syntax-parameter syntax-option syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-parameter syntax-shell\"> --</span>head                  <span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> other machines: ray start --address=HEAD:6379</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span></span></span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">doomformer</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> mnist<span class=\"syntax-variable syntax-parameter syntax-option syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-parameter syntax-shell\"> --</span>all</span><span class=\"syntax-variable syntax-parameter syntax-option syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-parameter syntax-shell\"> --</span>ray</span><span class=\"syntax-variable syntax-parameter syntax-option syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-parameter syntax-shell\"> --</span>record</span> mnist.json   <span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-begin syntax-shell\">#</span></span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\"> all 10,000 digits, one map each, on a cluster</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-shell\">\n</span></span></span></span></code></pre>\n<p>Budget one core and 1.3 GB of RAM per game. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/scaling.md#scaling-out-many-games-many-machines\">Scaling</a></p>\n<h2>More</h2>\n<table>\n<thead>\n<tr>\n<th>what</th>\n<th>try</th>\n<th>read</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Faster schedules: MNIST in one map from 5,696 to 272 tics</td>\n<td><code>--opt 3</code></td>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/scheduling.md\">scheduling</a></td>\n</tr>\n<tr>\n<td>A counter machine: 7 × 9 = 63 in 464 checked steps</td>\n<td><code>doomformer machine multiply 7 9</code></td>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/machine.md\">machine</a></td>\n</tr>\n<tr>\n<td>A SUBLEQ machine with self-modifying code</td>\n<td><code>doomformer machine subleq all</code></td>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/machine.md\">machine</a></td>\n</tr>\n<tr>\n<td>A blank brain learns digits in the map: 71 % held-out</td>\n<td><code>doomformer learn digits</code></td>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/learning.md\">learning</a></td>\n</tr>\n<tr>\n<td>PyTorch import with BatchNorm, pooling and QAT</td>\n<td><code>MLP.from_torch</code></td>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/interop.md\">interop</a></td>\n</tr>\n<tr>\n<td>A transformer that learned induction, exact in DOOM</td>\n<td><code>python -m demos.induction</code></td>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/models/induction/EVAL.md\">induction</a></td>\n</tr>\n<tr>\n<td>Patching, lesions and steering, checked in DOOM</td>\n<td><code>intref.forward(interventions=...)</code></td>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/interventions.md\">interventions</a></td>\n</tr>\n<tr>\n<td>Speed per pass and throughput</td>\n<td><code>doomformer bench</code></td>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/scaling.md\">scaling</a></td>\n</tr>\n</tbody>\n</table>\n<h2>Limits</h2>\n<p>Important</p>\n<ul>\n<li><strong>Slow.</strong> A small MLP runs about 23,000 times slower than NumPy. Most of the time goes to idle conveyor belts. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/HOW_IT_WORKS.md#speed\">Speed</a></li>\n<li><strong>Only the runs are checked.</strong> Inputs that never ran are not covered. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/verification.md#not-covered\">Not covered</a></li>\n<li><strong>Integer models.</strong> Attention is integer attention. No model has LayerNorm.</li>\n<li><strong>ViZDoom first.</strong> Other DOOM engines ran only small maps.</li>\n<li><strong>No reinforcement learning.</strong> The marine copies a scripted aimbot.</li>\n<li><strong>Finite machines.</strong> Memory is bounded. Nothing here claims DOOM is Turing complete.</li>\n<li><strong>Picked samples.</strong> Showcased seeds and names are picked. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/DEMOS.md#seeds-and-selection\">The list</a></li>\n</ul>\n<h2>What's in the box</h2>\n<table>\n<thead>\n<tr>\n<th>Path</th>\n<th>What it holds</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/doomformer\"><code>doomformer/</code></a></td>\n<td>the toolkit: map compiler, DOOM runtime, exact checks, CLI</td>\n</tr>\n<tr>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/demos\"><code>demos/</code></a></td>\n<td>research code: the marine's brain, the level generator, the fly circuit, the learning arena</td>\n</tr>\n<tr>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/training\"><code>training/</code></a></td>\n<td>training scripts for every model, with the data and sources</td>\n</tr>\n<tr>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/models\"><code>models/</code></a></td>\n<td>every trained model with its training log and evaluation</td>\n</tr>\n<tr>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/examples\"><code>examples/</code></a></td>\n<td>twelve one-file examples, most under 15 s</td>\n</tr>\n<tr>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/tests\"><code>tests/</code></a></td>\n<td>496 tests; CI runs them against real headless DOOM on Linux and macOS</td>\n</tr>\n<tr>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/README.md\"><code>docs/</code></a></td>\n<td>how it works, every demo with its numbers, the engine facts, the guide, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/docs/commands.md\">every command</a></td>\n</tr>\n<tr>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/CHANGELOG.md\"><code>CHANGELOG.md</code></a></td>\n<td>what each release added</td>\n</tr>\n</tbody>\n</table>\n<h2>Licensing</h2>\n<p>Code and docs: <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/LICENSE\">MIT</a>. Data keeps its own licence (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mottopanikeiku/doomformer/blob/main/THIRD_PARTY.md\">THIRD_PARTY.md</a>). The level-name lists come from the Doom Wiki (CC BY-SA 4.0) and id Software's source (GPL-2.0). The 100 sample MNIST digits are CC BY-SA 3.0. The fruit-fly circuits in <code>models/fly</code> come from the FlyWire connectome (CC BY-NC 4.0, non-commercial). Freedoom graphics are BSD-licensed. DOOM is a trademark of id Software / ZeniMax. This project is not affiliated with them.</p>\n",
  "content_markdown": "[![DOOMFORMER: the marine fights a horde of demons under a hellish sky](https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/banner_wide.png)](https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/banner_wide.png)\n\n**Neural networks computed by voodoo dolls inside DOOM maps.**\\\n Every value is read back and checked against NumPy. Tolerance 0.\n\n[![tests](https://github.com/mottopanikeiku/doomformer/actions/workflows/tests.yml/badge.svg)](https://github.com/mottopanikeiku/doomformer/actions/workflows/tests.yml) [![release](https://camo.githubusercontent.com/bd90ae1758c512eefd27c9166c2687910317d20c7e48a052a3b85b95d1b3918e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6d6f74746f70616e696b65696b752f646f6f6d666f726d65723f636f6c6f723d386230303030)](https://github.com/mottopanikeiku/doomformer/releases) [![Python 3.11+](https://camo.githubusercontent.com/96abf9b704f80578ea56dd10cab0d911c56d46dbec347f431ece9cf60ac175ad/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f707974686f6e2d332e31312532422d626c7565)](https://camo.githubusercontent.com/96abf9b704f80578ea56dd10cab0d911c56d46dbec347f431ece9cf60ac175ad/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f707974686f6e2d332e31312532422d626c7565) [![MIT](https://camo.githubusercontent.com/b8cadaa967891081f8f165695470689986c028821dd8a040132f6e661795dc0d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c7565)](https://github.com/mottopanikeiku/doomformer/blob/main/LICENSE) [![Open in Colab](https://camo.githubusercontent.com/eff96fda6b2e0fff8cdf2978f89d61aa434bb98c00453ae23dd0aab8d1451633/68747470733a2f2f636f6c61622e72657365617263682e676f6f676c652e636f6d2f6173736574732f636f6c61622d62616467652e737667)](https://colab.research.google.com/github/mottopanikeiku/doomformer/blob/main/examples/doomformer_colab.ipynb)\n\n[Quick start](https://github.com/mottopanikeiku/doomformer#quick-start) · [Walk a digit](https://github.com/mottopanikeiku/doomformer#walk-a-digit-doom-reads-it) · [The museum](https://github.com/mottopanikeiku/doomformer#the-museum-rewire-one-connection) · [How it works](https://github.com/mottopanikeiku/doomformer#how-it-works) · [What is checked](https://github.com/mottopanikeiku/doomformer#what-is-checked) · [Films](https://mottopanikeiku.github.io/doomformer/) · [Docs](https://github.com/mottopanikeiku/doomformer/blob/main/docs/README.md)\n\n| **10,000 / 10,000**     | **1,355**                     | **0**                            | **4**                                     |\n| ----------------------- | ----------------------------- | -------------------------------- | ----------------------------------------- |\n| MNIST test digits exact | voodoo dolls in one MNIST map | mismatches in 20,000 fuzzed nets | other DOOM engines run the museum exactly |\n\n[![A number is a crowd of voodoo dolls. A weight is a line on the floor. A sum is a light level or a height. An activation is a staircase. Attention is a ceiling. Every value is read back and compared with NumPy: tolerance 0.](https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/ladder.png)](https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/ladder.png)\n\n## Quick start\n\n```shell\npip install git+https://github.com/mottopanikeiku/doomformer   # Python 3.11+, Linux or macOS\ndoomformer hello             # 2 s: a small MLP, every value checked\ndoomformer draw --digit 7    # 15 s: the marine walks a 7 and the level reads it\n```\n\n`doomformer doctor` checks your setup. It builds ACC, the ACS compiler, if it is missing. That needs git, cmake and a C compiler. On Fedora: `sudo dnf install git cmake gcc gcc-c++ make`.\n\nTip\n\nNo install needed for the [Colab notebook](https://colab.research.google.com/github/mottopanikeiku/doomformer/blob/main/examples/doomformer_colab.ipynb). Draw a digit in your browser and DOOM reads it.\n\n## Walk a digit, DOOM reads it\n\n[![DrawPad: the marine walks a 7 across a 28x28 floor canvas, presses READ, and the winning voodoo doll lights a 7 on a 7-segment display](https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/drawpad.gif)](https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/drawpad.gif)\n\nThe marine holds FIRE and inks the floor. Then he presses READ.\n\n1,355 voodoo dolls in the same map run an MNIST network. The winning digit's doll crosses a line. That line lights the digit on the display.\n\n```\n          ▄▄▄▄▄▄▄▄▄▄▄▄▄▄\n       ▄████████████████\n       ████▀▀     ▀████▀\n       ▀▀▀        ▄███▀\n                  ████\n                  ███\n                  ███\n                  ███\n                 ████\n                 ███▀\n                 ████\n                 ▀███\n\nDOOM reads: 7  (right)   -- the winner's doll lit it on the 7-segment display\nEXACT: all 248 values DOOM computed [...] equal the NumPy integer reference (tolerance 0)\nREAD pass: 273 game tics = 8 s of real-time DOOM at 35 tics/s, 3 s wall [...]\n```\n\nPython reads back 248 values and checks every one. With `--digit`, Python presses the keys for you. Without it, you walk and draw yourself. [Full output](https://github.com/mottopanikeiku/doomformer/blob/main/docs/commands.md#doomformer-draw---digit-7)\n\nNote\n\nEXACT means DOOM got the same numbers as the integer network. It does not mean the digit is right.\n\n| run                                     | right           | exact  |\n| --------------------------------------- | --------------- | ------ |\n| first 100 MNIST test digits             | 99              | 100    |\n| 1,000 sampled test digits, one map each | 966             | 1,000  |\n| all 10,000 test digits, tile maps       | 9,716 (97.16 %) | 10,000 |\n\nThe float model scores 97.58 %. The network also trained on the strokes the scripted marine walks. [Details](https://github.com/mottopanikeiku/doomformer/blob/main/docs/drawpad.md) · [Film](https://mottopanikeiku.github.io/doomformer/#drawpad)\n\n[![eight MNIST test digits and what DOOM read: 7 2 1 0 4 9 6 3, all exact](https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/mnist.png)](https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/mnist.png)\n\n## The museum: rewire one connection\n\n[![Two views of one doll lane. Before MUTATE, DOOM reads 7 and the doll has passed its gate. After MUTATE, DOOM reads 1 and the same voodoo doll stands at its gate.](https://github.com/mottopanikeiku/doomformer/releases/download/v0.7.1/museum_mutate.png)](https://github.com/mottopanikeiku/doomformer/releases/download/v0.7.1/museum_mutate.png)\n\nTip\n\n**Play it without Python.** Download [museum.wad](https://github.com/mottopanikeiku/doomformer/releases/download/v0.7.1/museum.wad) ([sha256](https://github.com/mottopanikeiku/doomformer/releases/download/v0.7.1/museum_SHA256SUMS.txt)) and the free [Freedoom](https://freedoom.github.io/download.html) IWAD. Then run `gzdoom -iwad freedoom2.wad -file museum.wad`.\n\nStep on seven floor pads to light a digit. Press READ. 136 voodoo dolls run a tiny network and light the answer.\n\nPress MUTATE and the level rewires one connection while it runs. The same 7 now reads as 1. You can watch it happen: one doll stops at its gate.\n\n```\n$ doomformer museum verify\n7                        pads abc     w_7a +1  DOOM reads 7  scores [4, 6, 3, 5, 4, 3, 2, 7, 3, 4]  EXACT (148 values; 744 tics; [...])\n7 after MUTATE           pads abc     w_7a -1  DOOM reads 1  scores [4, 6, 3, 5, 4, 3, 2, 5, 3, 4]  EXACT (148 values; 744 tics; [...])\n7 after RESTORE          pads abc     w_7a +1  DOOM reads 7  scores [4, 6, 3, 5, 4, 3, 2, 7, 3, 4]  EXACT (148 values; 744 tics; [...])\n```\n\nA self-test version runs exactly in GZDoom, LZDoom, UZDoom and ZDoom 2.8.1. [Details](https://github.com/mottopanikeiku/doomformer/blob/main/docs/museum.md)\n\n## How it works\n\nEvery part of a network becomes a part of the map:\n\n| in a neural network  | in the DOOM map                                                |\n| -------------------- | -------------------------------------------------------------- |\n| a value of 5         | 5 voodoo dolls                                                 |\n| a weight             | a line on the floor; each doll that crosses it adds the weight |\n| a sum                | a sector's light level or floor height                         |\n| an activation (ReLU) | a staircase of gates the dolls must climb                      |\n| attention            | dolls squeezing under ceilings that another value lowered      |\n| a lesion             | a closed door                                                  |\n\nOne layer, from dolls to dolls:\n\n```\nflowchart LR\n    A[\"input value<br/>= a crowd of dolls\"] --> B[\"weight lines<br/>each crossing adds w\"]\n    B --> C[\"the sum<br/>= a light level or height\"]\n    C --> D[\"staircase of gates<br/>= the activation\"]\n    D --> E[\"next layer's dolls\"]\n```\n\n Loading\n\nThe engine has sharp edges, and the compiler works around them:\n\n- A floor mover ignores a second request while it is still moving.\n- A teleport cancels lines a doll crossed earlier in the same tic.\n- Things far from a BSP node can land in the wrong room, so every map fits in 32,000 units.\n\n`doomformer facts` checks these in about 10 s. [Engine facts](https://github.com/mottopanikeiku/doomformer/blob/main/docs/HOW_IT_WORKS.md#engine-facts) · [Engine features it needs](https://github.com/mottopanikeiku/doomformer/blob/main/docs/HOW_IT_WORKS.md#engine-features-it-needs) · [Other ports](https://github.com/mottopanikeiku/doomformer/blob/main/docs/engine_limits.md#other-ports)\n\nComputers in DOOM maps are not new. [counter.wad](https://www.wad-archive.com/wad/8d0de31d8b392fc2d7fd817e933b3cf43bca799a) counts with voodoo dolls, [conway.wad](https://github.com/pwiecz/conway.wad) runs Game of Life, and [Danny Spencer's calculator](https://github.com/nukep/doom-calculator) adds numbers. New here: a compiler for neural networks, and an exact check on every value. [Related work](https://github.com/mottopanikeiku/doomformer/blob/main/docs/related_work.md)\n\n## What is checked\n\n[![Pipeline: your network becomes integers and a DOOM map, ViZDoom runs it and Python reads the values back (light levels and plane heights). A NumPy integer reference, which never sees the map, computes the same values. Every value is compared with tolerance 0: EXACT or MismatchError.](https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/pipeline.png)](https://github.com/mottopanikeiku/doomformer/releases/download/v0.4.0/pipeline.png)\n\nEvery run compares each value the map exposes with NumPy. That proves the inputs that ran, nothing more. So the repo also attacks its own check:\n\n| attack                                                    | result                                              |\n| --------------------------------------------------------- | --------------------------------------------------- |\n| **Tamper** with one weight line                           | the check fails on exactly the inputs that cross it |\n| **Fuzz** 20,000 random nets at the range limits           | 0 mismatches; CI fuzzes a fresh seed on every push  |\n| **Mutate** one line of a map, 1,004 times                 | 297 caught; no survivor is proven harmless          |\n| **Extract** the weights back out of the map, without DOOM | equal to the source net                             |\n| **Guard** every readout page with a poison value          | a page that never runs cannot pass old values       |\n\nThe MNIST map exposes 248 values. It does not expose its 903 staircase counts and 1,351 gate comparisons. Those are checked only through the sums they feed. Fuzzing and tests found four bugs in the compiler. All are fixed. [Verification](https://github.com/mottopanikeiku/doomformer/blob/main/docs/verification.md)\n\n**Who computes what**\n\n| run                                           | Python                                                     | voodoo dolls                                     |\n| --------------------------------------------- | ---------------------------------------------------------- | ------------------------------------------------ |\n| `mnist`, `df.compile`                         | writes the inputs, waits, reads                            | every sum, activation, comparison and the choice |\n| `demo`, `ask` (tile maps)                     | writes tokens, copies values between maps, samples letters | every sum and activation                         |\n| `draw`, `--loop`, the marine's brain, the fly | only advances the clock and reads                          | everything, including the choice                 |\n| `machine`                                     | loads the program, then advances the clock and reads       | program counter and registers                    |\n| `museum`, played in GZDoom                    | nothing                                                    | every sum, comparison and the choice             |\n\nACS level scripts move gates, rewind the dolls, sense the world and copy results out. Two do more. `df.Agent` takes an argmax in ACS. `--opt 3` copies each layer's values into the next layer with a script. [Per demo](https://github.com/mottopanikeiku/doomformer/blob/main/docs/HOW_IT_WORKS.md#who-does-what-per-demo)\n\nThe maps need ZDoom (UDMF and ACS). This repo runs [ViZDoom](https://github.com/Farama-Foundation/ViZDoom) 1.3.2 with Freedoom assets.\n\n## Commands\n\n| Command                                           | What DOOM does                             | Time         | Skill level          |\n| ------------------------------------------------- | ------------------------------------------ | ------------ | -------------------- |\n| `doomformer hello`                                | a small MLP, 5 random inputs               | 2 s          | I'm too young to die |\n| `doomformer draw --digit 7`                       | the marine walks a 7, the level reads it   | 15 s         | Hey, not too rough   |\n| `doomformer museum build`                         | a playable map that reads a digit          | 1 s          | Hey, not too rough   |\n| `doomformer mnist`                                | reads 4 test digits, or your own image     | 1.5 to 3 min | Hurt me plenty       |\n| `doomformer demo`                                 | a transformer writes a level name          | 15 to 60 s   | Hurt me plenty       |\n| `doomformer machine subleq all`                   | a tiny computer runs three programs        | about 5 min  | Ultra-Violence       |\n| `doomformer learn digits --classes 4 --steps 300` | a blank brain learns digits inside the map | about 5 min  | Ultra-Violence       |\n| `doomformer ask \"what does iddqd do\"`             | answers from 189 DOOM facts                | about 11 min | Ultra-Violence       |\n| `doomformer demo --nightmare`                     | the 2-layer model, 106 tile maps           | 3.5 to 7 min | Nightmare!           |\n\nTimes are from a 16-core arm64 Linux machine. [Every command](https://github.com/mottopanikeiku/doomformer/blob/main/docs/commands.md)\n\nSome outputs are picked. DEMON CANYON, the name `--nightmare` writes, is one hand-picked sample. `ask` gets 94.7 % of its training questions right, and 35.4 % of new wordings.\n\n## Bigger experiments\n\n[![His brain is the level: the marine fights a demon while 1,345 dots on the right, voodoo dolls of him, run his policy transformer](https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/hero.gif)](https://github.com/mottopanikeiku/doomformer/releases/download/v0.1.0/hero.gif)\n\n**His brain is the level.** The level senses the nearest demon. 1,345 voodoo dolls of the marine run his brain and pick an action. The level turns him and fires. Python only steps the clock and reads. 50 of 50 decisions are exact. [Film](https://mottopanikeiku.github.io/doomformer/#brain) · [Code](https://github.com/mottopanikeiku/doomformer/blob/main/demos/brainlevel.py)\n\nWarning\n\nHe is not playable. One decision takes 22 s of game time, and the demons are frozen while he thinks. With the demons awake (`--live`), he dies in 5.5 s without a kill. [Live demons](https://github.com/mottopanikeiku/doomformer/blob/main/docs/DEMOS.md#live-demons-what-the-latency-costs-him)\n\n| run it from a clone                             | what you see                                          |\n| ----------------------------------------------- | ----------------------------------------------------- |\n| `python -m demos.brainlevel`                    | his brain is the level                                |\n| `python -m demos.brainlevel --live`             | the same brain against awake demons                   |\n| `python -m demos.brainlevel --lesion-when near` | the level closes neuron doors when a demon gets close |\n| `python -m demos.aimlearn`                      | a perceptron learns to aim inside one game            |\n| `python -m demos.flyloop`                       | a fruit-fly circuit drives the marine                 |\n| `python -m demos.lobotomy`                      | lesions that turn him into a pacifist                 |\n\n[All demos, numbers and picked seeds](https://github.com/mottopanikeiku/doomformer/blob/main/docs/DEMOS.md)\n\n## Build your own\n\nCompile a network into a map. Let its outputs open doors, flash lights or shove the marine. This runs as pasted:\n\n```python\nimport numpy as np\nimport doomformer as df\n\n# 2 inputs -> [a AND b, a OR b] -> 2 outputs, all integers\nnet = df.MLP(\n    weights=[np.array([[1, 1], [1, 1]]), np.array([[1, 0], [0, 1]])],\n    biases=[np.array([-1, 0]), np.array([0, 0])],\n    thresholds=[np.array([1]), np.array([1])],\n    signed_input=False,\n)\nwith df.compile(net) as brain:\n    for x in ([0, 0], [1, 0], [1, 1]):\n        # computed by voodoo dolls; raises df.MismatchError on any difference from net.reference\n        print(x, \"->\", brain(np.array(x)).tolist())\n    brain.record([np.array([0, 1]), np.array([1, 1])], \"dolls.gif\")   # film the dolls doing it\n```\n\n`df.MLP.from_torch` converts a PyTorch model ([example 02](https://github.com/mottopanikeiku/doomformer/blob/main/examples/02_pytorch_to_doom.py)). The `world` and `actions` hooks wire outputs to doors, lights and thrusts ([example 03](https://github.com/mottopanikeiku/doomformer/blob/main/examples/03_brain_opens_doors.py)). [Guide](https://github.com/mottopanikeiku/doomformer/blob/main/docs/BUILD_YOUR_OWN.md) · [12 examples](https://github.com/mottopanikeiku/doomformer/blob/main/examples) · [Show and tell](https://github.com/mottopanikeiku/doomformer/issues/new/choose)\n\n## Many games at once\n\nOne map runs in one game, on one core. `df.run_many` spreads inputs over many games, or over a Ray cluster. A network can also be split into tile maps, one per layer. Then Python copies values between them.\n\n| run                  | digits | right | exact  | time   |\n| -------------------- | ------ | ----- | ------ | ------ |\n| one map, 14 games    | 1,000  | 966   | 1,000  | 2 h    |\n| 4 tile maps, 6 games | 10,000 | 9,716 | 10,000 | 23 min |\n\n```shell\ndoomformer mnist --tiles --all --workers 6         # all 10,000 digits as tile maps, about 23 min\npip install \"doomformer[ray]\"\nray start --head                  # other machines: ray start --address=HEAD:6379\ndoomformer mnist --all --ray --record mnist.json   # all 10,000 digits, one map each, on a cluster\n```\n\nBudget one core and 1.3 GB of RAM per game. [Scaling](https://github.com/mottopanikeiku/doomformer/blob/main/docs/scaling.md#scaling-out-many-games-many-machines)\n\n## More\n\n| what                                                      | try                                 | read                                                                                           |\n| --------------------------------------------------------- | ----------------------------------- | ---------------------------------------------------------------------------------------------- |\n| Faster schedules: MNIST in one map from 5,696 to 272 tics | `--opt 3`                           | [scheduling](https://github.com/mottopanikeiku/doomformer/blob/main/docs/scheduling.md)       |\n| A counter machine: 7 × 9 = 63 in 464 checked steps        | `doomformer machine multiply 7 9`   | [machine](https://github.com/mottopanikeiku/doomformer/blob/main/docs/machine.md)             |\n| A SUBLEQ machine with self-modifying code                 | `doomformer machine subleq all`     | [machine](https://github.com/mottopanikeiku/doomformer/blob/main/docs/machine.md)             |\n| A blank brain learns digits in the map: 71 % held-out     | `doomformer learn digits`           | [learning](https://github.com/mottopanikeiku/doomformer/blob/main/docs/learning.md)           |\n| PyTorch import with BatchNorm, pooling and QAT            | `MLP.from_torch`                    | [interop](https://github.com/mottopanikeiku/doomformer/blob/main/docs/interop.md)             |\n| A transformer that learned induction, exact in DOOM       | `python -m demos.induction`         | [induction](https://github.com/mottopanikeiku/doomformer/blob/main/models/induction/EVAL.md)  |\n| Patching, lesions and steering, checked in DOOM           | `intref.forward(interventions=...)` | [interventions](https://github.com/mottopanikeiku/doomformer/blob/main/docs/interventions.md) |\n| Speed per pass and throughput                             | `doomformer bench`                  | [scaling](https://github.com/mottopanikeiku/doomformer/blob/main/docs/scaling.md)             |\n\n## Limits\n\nImportant\n\n- **Slow.** A small MLP runs about 23,000 times slower than NumPy. Most of the time goes to idle conveyor belts. [Speed](https://github.com/mottopanikeiku/doomformer/blob/main/docs/HOW_IT_WORKS.md#speed)\n- **Only the runs are checked.** Inputs that never ran are not covered. [Not covered](https://github.com/mottopanikeiku/doomformer/blob/main/docs/verification.md#not-covered)\n- **Integer models.** Attention is integer attention. No model has LayerNorm.\n- **ViZDoom first.** Other DOOM engines ran only small maps.\n- **No reinforcement learning.** The marine copies a scripted aimbot.\n- **Finite machines.** Memory is bounded. Nothing here claims DOOM is Turing complete.\n- **Picked samples.** Showcased seeds and names are picked. [The list](https://github.com/mottopanikeiku/doomformer/blob/main/docs/DEMOS.md#seeds-and-selection)\n\n## What's in the box\n\n| Path                                                                                   | What it holds                                                                                                                                                     |\n| -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| [`doomformer/`](https://github.com/mottopanikeiku/doomformer/blob/main/doomformer)    | the toolkit: map compiler, DOOM runtime, exact checks, CLI                                                                                                        |\n| [`demos/`](https://github.com/mottopanikeiku/doomformer/blob/main/demos)              | research code: the marine's brain, the level generator, the fly circuit, the learning arena                                                                       |\n| [`training/`](https://github.com/mottopanikeiku/doomformer/blob/main/training)        | training scripts for every model, with the data and sources                                                                                                       |\n| [`models/`](https://github.com/mottopanikeiku/doomformer/blob/main/models)            | every trained model with its training log and evaluation                                                                                                          |\n| [`examples/`](https://github.com/mottopanikeiku/doomformer/blob/main/examples)        | twelve one-file examples, most under 15 s                                                                                                                         |\n| [`tests/`](https://github.com/mottopanikeiku/doomformer/blob/main/tests)              | 496 tests; CI runs them against real headless DOOM on Linux and macOS                                                                                             |\n| [`docs/`](https://github.com/mottopanikeiku/doomformer/blob/main/docs/README.md)      | how it works, every demo with its numbers, the engine facts, the guide, [every command](https://github.com/mottopanikeiku/doomformer/blob/main/docs/commands.md) |\n| [`CHANGELOG.md`](https://github.com/mottopanikeiku/doomformer/blob/main/CHANGELOG.md) | what each release added                                                                                                                                           |\n\n## Licensing\n\nCode and docs: [MIT](https://github.com/mottopanikeiku/doomformer/blob/main/LICENSE). Data keeps its own licence ([THIRD\\_PARTY.md](https://github.com/mottopanikeiku/doomformer/blob/main/THIRD_PARTY.md)). The level-name lists come from the Doom Wiki (CC BY-SA 4.0) and id Software's source (GPL-2.0). The 100 sample MNIST digits are CC BY-SA 3.0. The fruit-fly circuits in `models/fly` come from the FlyWire connectome (CC BY-NC 4.0, non-commercial). Freedoom graphics are BSD-licensed. DOOM is a trademark of id Software / ZeniMax. This project is not affiliated with them.\n",
  "dateCreated": "2026-10-30T13:27:01.845275939+00:00",
  "date_created": "2026-10-29T23:25:46+00:00",
  "date_modified": "2026-10-29T23:25:46+00:00",
  "date_published": "2026-10-29T23:25:46+00:00",
  "description": "Instead of trying to run DOOM on things, I have instead decided to use DOOM (many, many, many doom games actually) to create a transformer. For a lot of the math required I essentially had to use DOOM game mechanics and voodoo dolls (DOOM…",
  "external_url": "https://github.com/mottopanikeiku/doomformer",
  "git": {
    "commit": "20068632b65d2830a2d54f25ca1d90d697bea2c0",
    "path": "items/hnrss-org/2026/10/2026-10-29-show-hn-i-turned-doom-into-a-transformer.md",
    "permalink": "https://github.com/aymericbeaumet/aggr-instance/blob/20068632b65d2830a2d54f25ca1d90d697bea2c0/items/hnrss-org/2026/10/2026-10-29-show-hn-i-turned-doom-into-a-transformer.md"
  },
  "id": "urn:aggr:item:535555895ff60c769ef75b5e1b7cb8da0b6770f4",
  "isBasedOn": {
    "@id": "https://github.com/mottopanikeiku/doomformer"
  },
  "mainEntity": {
    "@id": "https://github.com/mottopanikeiku/doomformer",
    "@type": "CreativeWork",
    "archivedAt": {
      "@id": "https://aggr.aymericbeaumet.com/items/hnrss-org/2026-10-29-show-hn-i-turned-doom-into-a-transformer/#webpage"
    },
    "author": [
      {
        "@type": "Person",
        "name": "falperc"
      }
    ],
    "dateModified": "2026-10-29T23:25:46+00:00",
    "datePublished": "2026-10-29T23:25:46+00:00",
    "headline": "Show HN: I Turned DOOM into a Transformer",
    "image": {
      "@type": "ImageObject",
      "caption": "Compile an integer neural network into a DOOM map. Voodoo dolls do the arithmetic, light levels and plane heights hold the values, and every value is checked against NumPy with tolerance 0. - motto...",
      "height": 90,
      "url": "https://opengraph.githubassets.com/d50a922bf1f026e7565a24975ecea3d2802a9b09c5c9978aaaa4826c4110d428/mottopanikeiku/doomformer",
      "width": 160
    },
    "timeRequired": "PT9M",
    "url": "https://github.com/mottopanikeiku/doomformer",
    "wordCount": 2007
  },
  "name": "Archived snapshot: Show HN: I Turned DOOM into a Transformer",
  "preview": {
    "alt": "Compile an integer neural network into a DOOM map. Voodoo dolls do the arithmetic, light levels and plane heights hold the values, and every value is checked against NumPy with tolerance 0. - motto...",
    "color": null,
    "height": 90,
    "placeholder": {
      "data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=",
      "hash": ""
    },
    "url": "https://opengraph.githubassets.com/d50a922bf1f026e7565a24975ecea3d2802a9b09c5c9978aaaa4826c4110d428/mottopanikeiku/doomformer",
    "width": 160
  },
  "reading_minutes": 9,
  "replicated_at": null,
  "source": "hnrss-org",
  "source_name": "Hacker News: Front Page",
  "summary": "Instead of trying to run DOOM on things, I have instead decided to use DOOM (many, many, many doom games actually) to create a transformer. For a lot of the math required I essentially had to use DOOM game mechanics and voodoo dolls (DOOM is turing complete btw) and exchange them with the actual operations, essentially creating an alternative to NumPy (a 65000x slower one). Thus, I am proud to present DOOMFORMER. Here are a list of things DOOMFORMER can do : It can classify MNIST digits, even if you write these digits on the map! It can talk(kinda) You can use it to make decisions, so, it can play DOOM. Yes! You can play DOOM with thousands of DOOM games now! The marine's mind can be controlled by DOOM, playing on a map generated by DOOMFORMER. Truly, the possibilities are endless, and even larger-scale training of DOOMFORMER could be done on a measly T4. If anyone would like to help me scale this up and make crazier things, I'd love to work together. Comments URL: https://news.ycombinator.com/item?id=50297697 Points: 110 # Comments: 34",
  "tags": [],
  "temporalCoverage": "2026-10-30T13:27:01.845275939+00:00",
  "title": "Show HN: I Turned DOOM into a Transformer",
  "url": "https://aggr.aymericbeaumet.com/items/hnrss-org/2026-10-29-show-hn-i-turned-doom-into-a-transformer/",
  "word_count": 2007
}