Adding a Z axis to Core War
How ZoreWars turns Core War's single ring of memory into a plane and a 3D volume without breaking the classic game, and what changed about which warriors win.

Core War has been played on a ring of memory since 1984. Every address is a distance along that ring, every instruction runs one cell after the last, and decades of strategy are built on that one dimension. For ZoreWars I wanted to add more dimensions without breaking any of it.
The result is a game with three battlefields: the classic ring, a 2D plane and a 3D volume. All three run the same instruction set. This post covers how that works, how I kept the classic game safe, and what the new shapes did to the strategies that win.
Every number is a point
Redcode fields hold one number each. I kept it that way. On a plane or volume, that number is read as a point on a torus, in mixed radix: the first part is x, then y, then z. A plain number like 1 or -1 is still a step along the row, exactly as in classic Redcode, so most existing code still makes sense. [0,1] means one row down, and [0,0,1] one layer in.
The split that mattered was deciding which operations work per axis and which stay plain numbers. Addressing and ADD, SUB, MUL, DIV and MOD work per axis, each wrapping on its own. Counters (DJN) and pointer increments stay plain numbers, so a loop still counts normally and a pointer that walks forward visits every cell, row by row.
Because storage is unchanged, everything built on it kept working: P-space, replays, post-mortems and the tools.
Keeping the ring safe
The classic game has an outside reference: pMARS, the simulator the public hills use. The new shapes don't. I relied on two checks.
The first is mathematical. A torus one row high is the classic ring. A permanent test runs the library and 34 historical warriors on an 8000×1 torus and checks that every round matches the pMARS-verified ring.
The second is a second interpreter. scripts/plane-reference.js was written separately from the rules, keeping cells by (x, y, z) instead of by number. A fuzzer runs random programs through both and compares every cell and every process after every step. 581,477 steps agree. Along the way it found a loading bug: code longer than half a row was loaded across two rows while execution wrapped inside one. That's why a warrior on a torus can be at most half a row long.
Headings and TRN
On the first version of the plane, code could only flow along rows. An imp circled its own row of 100 cells forever. To move vertically, a warrior had to copy itself and jump.
So every process got a heading: plus or minus x, y or z, starting at +x. The next instruction is one step along the heading. One new instruction, TRN, turns the process to face along a vector. Jumps keep the heading, and child processes inherit it. On the ring, TRN is an assembler error and no heading ever changes, so classic Core War stays exactly as it was.
That made new shapes of warrior possible. Lift is an imp that climbs through the layers. Pillar is a bomber standing in a column, one cell wide in every row, and it beats the same bomber lying in a row in most matchups.
What the new shapes changed
The biggest surprise was arithmetic. On an 8,000-cell ring, a well-chosen stride can reach every cell. On a 100×80 plane no fixed step can visit more than 400 cells, because the two axes don't share a cycle. On a 40×20×10 volume a fixed step repeats within 40 cells, half a percent of the space.
That breaks the classic bomber and the classic scanner, both of which rely on one stride. In a plane tournament, linear core clears came first, papers (replicators) were nearly impossible to kill, and stride-based warriors fell to about one point per round. Warriors whose JavaScript generators assumed ring arithmetic bombed themselves until they were rewritten with SIZEX and SIZEY.
In the volume, clears became the local optimum. An evolver run started from three strong warriors ended up rediscovering the best clear with one harmless change.
What brought variety back was a warrior called Leapfrog. A clear can't be hidden from, but its front is predictable and its code doesn't move. Leapfrog plants a marker in the direction the front will come from, watches it, and when it changes, copies itself behind the front. It beats every clear and loses to every paper. With papers tying clears, the volume has a rock-paper-scissors triangle again, and switchers that use P-space to change strategy between rounds score best.
Keeping the failures
Not every idea worked. Trap-laying clears, a clear that dodges other clears, swarms of scanners that recognise each other: each was built, measured and dropped. Instead of deleting them, they live in warriors/prototypes/, runnable, with their scores and a note on why they lost, so the next person to try the idea starts from the numbers.
The plane and volume are still experimental and still changing. If you want to try writing for them, the arena opens a 3D battle in one click, and the ZoreWars project page has the rest of the links. The companion post covers how the game was tested.