COREDUEL

TUTORIAL

Welcome to Core War

This is a programming game. You write a bot in Redcode, a tiny assembly language, and drop it into the core: a ring of 8000 memory cells shared with the enemy bots. Each bot runs one instruction per turn. There are no walls and no rules of engagement: whoever overwrites the other's code, or stays alive longer, wins the round. The Arena shows the whole core as pixels, so you can watch your program crawl, bomb and scan in real time.

The lessons below start with a one-line bot and end with a warrior that changes strategy between rounds. You can skip ahead or come back at any time with the step list. Every lesson has a complete bot: open it in the editor, run it, then change one number and run it again.

Lesson 0: How to play

Lesson 1: The Imp

The core is a ring of 8000 cells. A process executes one cell per turn and moves to the next. MOV copies a cell. With the .I modifier it copies the whole instruction, and #0 means "this very instruction".

;redcode-94
;name Imp
;author Tutorial
;strategy Copies itself one cell forward, forever.
        MOV.I   #0, 1
        END

Each turn the Imp copies itself to the next cell and then executes that copy. It crawls through the whole core, overwriting everything in its path. It cannot be killed by a single DAT (it just copies over it), but it also never kills anything by itself: it usually ends in a tie.

Run it against Dwarf from the library and watch the green trail.

Lesson 2: Dwarf, the bomber

A DAT kills the process that executes it. Dwarf throws DATs at every fourth cell, so any warrior longer than 3 cells is hit eventually.

;redcode-94
;name Dwarf
;author Tutorial
;strategy Drops a DAT every 4 cells.
        ORG     start
target  DAT.F   #0, #0
start   ADD.AB  #4, target
        MOV.AB  #0, @target
        JMP     start
        END

Why 4? 8000 is divisible by 4, so the pointer walks 2000 cells and returns exactly to target, which is a DAT already. Dwarf never bombs its own three code lines.

Lesson 3: Modifiers

The modifier picks which fields move. Compare:

Dwarf above uses ADD.AB so the immediate 4 (an A-field) lands in target's B-field. Here is a Dwarf that throws whole DAT instructions with MOV.I. Its bomb has predecrement operands: when an enemy process executes it, both operands are still evaluated before the process dies, so two more cells far away get damaged too.

;redcode-94
;name Dwarf Plus
;author Tutorial
;strategy Full-instruction DAT bombs with decrementing fields.
        ORG     start
ptr     DAT     #0, #0
bomb    DAT     <2667, <5334
start   ADD.AB  #4, ptr
        MOV.I   bomb, @ptr
        JMP     start
        END

Compare Dwarf against Dwarf Plus with the same seed several times.

Lesson 4: Addressing modes and the imp gate

Both operands are evaluated every instruction, even ones JMP ignores. < decrements the B-field of the addressed cell before using it. A JMP that keeps decrementing a cell is an imp gate: when an Imp copy (MOV.I 0, 1) lands there, its B-field becomes 0, so it copies onto itself and the process runs into empty core and dies.

;redcode-94
;name Gated Dwarf
;author Tutorial
;strategy Dwarf whose loop instruction also gates the cell before it.
        ORG     start
gate    DAT     #0, #0
target  DAT     #0, #0
start   ADD.AB  #4, target
        MOV.AB  #0, @target
        JMP     start, <gate
        END

Run Gated Dwarf against Imp: the Imp now usually dies instead of tying (the gate fires once per loop, so it needs a few laps). Since target and start are 1 and 2 cells after gate, and the bombs fall at multiples of 4 from target, the gate is never bombed.

Lesson 5: SPL and the imp ring

SPL starts a second process. Processes of one warrior take turns. Three imps spaced 2667 cells apart (3 x 2667 = 8001, one more than the core) chase each other and advance one cell every three copies: an imp ring. It is much harder to gate than a single imp.

;redcode-94
;name Imp Ring
;author Tutorial
;strategy 3-point imp ring launched with SPL.
step    EQU     2667
        ORG     start
start   MOV.I   imp, imp+step
        MOV.I   imp, imp+2*step
        SPL     imp+step
        SPL     imp+2*step
        JMP     imp
imp     MOV.I   #0, step
        END

EQU defines a constant. imp+2*step is an expression, evaluated by the assembler. Try step = 4001 with two imps.

Lesson 6: Scanners

A scanner looks for the enemy before bombing. Empty core is DAT 0, 0, so a non-zero B-field means "something is here". JMZ jumps if the tested field is zero.

;redcode-94
;name Scanner
;author Tutorial
;strategy Scan every 3039th cell for a non-zero B-field, bomb it.
step    EQU     3039
        ORG     scan
ptr     DAT     #0, #0
bomb    DAT     #0, #0
scan    ADD.AB  #step, ptr
        JMZ.B   scan, @ptr
        MOV.I   bomb, @ptr
        JMP     scan
        END

Against Dwarf the scanner finds the bomber's code quickly. Against an Imp it wastes bombs on the trail. A real scanner uses an odd step that never revisits a cell and skips over its own code.

Lesson 7: Bootstrapping

The code you load is a fixed target. Copy the real warrior far away, jump there, and let the enemy waste bombs on the launcher. A MOV loop with predecrement pointers copies backwards; DJN with an immediate counts the iterations on its own B-field.

;redcode-94
;name Boot Dwarf
;author Tutorial
;strategy Copies Dwarf 3000 cells away and runs the copy.
dist    EQU     3000
len     EQU     4
        ORG     boot
boot    MOV.I   <src, <dst
        DJN     boot, #len
        JMP     dwarf+1+dist
src     DAT     #0, dwarf+len
dst     DAT     #0, dwarf+len+dist
dwarf   DAT.F   #0, #0
        ADD.AB  #4, dwarf
        MOV.AB  #0, @dwarf
        JMP     dwarf+1
        END

Lesson 8: P-space, learning between rounds

Each warrior keeps 500 private cells across the rounds of a match. Cell 0 says how the last round went: 0 = we died, 1 = we won, 2 = tie. LDP loads a cell, STP stores one. This warrior remembers which strategy it ran in cell 1 and switches whenever it lost.

;redcode-94
;name Switcher
;author Tutorial
;strategy Runs Dwarf or an imp ring; switches after a lost round.
step    EQU     2667
        ORG     start
res     DAT     #0, #0
cur     DAT     #0, #0
start   LDP.AB  #0, res         ; res.B = last result
        LDP.AB  #1, cur         ; cur.B = strategy 0 or 1
        JMN.B   keep, res       ; did not lose: keep it
        MUL.AB  #-1, cur        ; toggle 0 <-> 1
        ADD.AB  #1, cur
keep    STP.B   cur, #1         ; remember it
        JMZ.B   dwarf, cur
        MOV.I   imp, imp+step
        MOV.I   imp, imp+2*step
        SPL     imp+step
        SPL     imp+2*step
        JMP     imp
imp     MOV.I   #0, step
target  DAT.F   #0, #0
dwarf   ADD.AB  #4, target
        MOV.AB  #0, @target
        JMP     dwarf
        END

Run a 10-round match against Scanner and watch the strategy flip after losses. Real p-space warriors ("pswitchers") pick from several components and are a large part of modern tournament play.

Where next