REDCODE MANUAL
CoreDuel implements the ICWS'94 standard with the pMARS extensions (p-space, FOR/ROF, EQU expressions). If you know pMARS, everything here should look familiar.
0. What this game is
You write small programs, bots, and send them into the Arena to fight other bots. A bot is written in Redcode, an assembly-like language with 19 instructions. All bots of a match are loaded into one shared memory, the core: a ring of 8000 cells (the end wraps around to the start) inside a simple emulated computer called MARS. Nothing else exists in that computer: no screen, no files, only instructions in cells and a few processes that execute them.
Every bot starts with one process at a random position, at least 100 cells away from the others. The emulator gives the bots turns in rotation; on its turn a bot executes one instruction of one of its processes. A process dies when it executes a DAT instruction (or divides by zero); a bot dies when its last process is gone. Because all bots share the memory, the way to win is to overwrite the opponent's code with DAT bombs, scan the core for it, or flood the core with copies of yourself, while keeping your own code alive.
A round ends when only one bot is left or after 80000 cycles. A match is one or more rounds; the survivors of each round score points and the best total wins. That is the whole game: write a better program than the other player.
How to start:
- Bots: fork a classic from the library (Imp, Dwarf) or write a new one; the editor checks your code as you type.
- Arena: fill the bot slots (one bot alone is a test run), set rounds and speed, START, watch the core.
- Tutorial: eight short lessons that build a working bot step by step. The rest of this manual is the language reference.
1. The core
The core is a ring of 8000 cells. Each cell holds one instruction. Addresses wrap: cell 7999 + 1 = cell 0. There are no absolute addresses in Redcode; every address is relative to the instruction that uses it.
Before a round every cell is DAT.F $0, $0. Warriors are placed at random positions at least MINDISTANCE (100) cells apart. Each warrior starts with one process at its ORG.
Processes take turns: warrior A executes one instruction, then warrior B, and so on. A warrior with several processes runs them round-robin, one per turn.
A process dies when it executes DAT, or divides by zero. A warrior dies when its last process dies. The round ends when one warrior is left or after MAXCYCLES (80000) cycles.
2. Program layout
;redcode-94
;name Dwarf
;author A. K. Dewdney
;strategy Bombs every 4th cell.
;assert CORESIZE == 8000
ORG start
target DAT.F #0, #0
start ADD.AB #4, target
MOV.AB #0, @target
JMP start
END
- Everything after
;is a comment. The lines;name,;authorand;strategyare shown in the bot list and in the arena. ;assert EXPRmust be true or the warrior is rejected. Use it to state which core size you tuned for.- Text before
;redcode(mail headers, prose) is ignored. - Labels start a line. A trailing colon is allowed (
start: ADD ...). Labels are case-sensitive. - Opcodes, modifiers and modes are case-insensitive.
- A program may have at most
MAXLENGTH(100) instructions.
3. Instruction syntax
label OPCODE.MOD A-mode A-value, B-mode B-value ; comment
Every instruction has an opcode, a modifier, an A operand and a B operand. Each operand is an addressing mode plus a value. Values are expressions (see 8) evaluated relative to the instruction's own address.
If you write only one operand, the assembler fills the other one:
DAT xbecomesDAT #0, x.- For every other opcode the single operand is A and B becomes
$0.
4. Addressing modes
Every operand is resolved to a pointer (a cell address) before the opcode runs. Both operands are always evaluated, A first, even when the opcode ignores one of them. That is why pre/post-increment side effects happen even in JMP.
#immediate. The pointer is the current instruction itself; the value is used as a number.$direct (the default). Pointer = here + value.@B-indirect. Pointer = (here + value) + B-field of that cell.<B-predecrement indirect. Decrement the B-field of cell (here + value) first, then as@.>B-postincrement indirect. As@, then increment the B-field of that cell.*A-indirect. As@, but through the A-field.{A-predecrement indirect. As<, through the A-field.}A-postincrement indirect. As>, through the A-field.
Note: in ICWS'94 the immediate operand still has a pointer, the instruction itself. MOV.I #0, 1 copies the whole instruction one cell forward. This is the classic Imp.
5. Modifiers
The modifier says which fields the opcode reads and writes. For an instruction with A-pointer a and B-pointer b:
.AA-field of a to A-field of b..BB-field of a to B-field of b..ABA-field of a to B-field of b..BAB-field of a to A-field of b..Fboth fields, A to A and B to B..Xboth fields crossed, A to B and B to A..Ithe whole instruction, opcode and modes included.MOVonly; for arithmetic.Ibehaves like.F.
Default modifier when you omit it:
DAT,NOP:.FMOV,CMP,SEQ,SNE:.ABif A is immediate,.Bif B is immediate, else.IADD,SUB,MUL,DIV,MOD:.ABif A is immediate,.Bif B is immediate, else.FSLT,LDP,STP:.ABif A is immediate, else.BJMP,JMZ,JMN,DJN,SPL:.B
6. Opcodes
DATKills the process that executes it. Also the usual data cell and bomb.MOVCopies from A to B.ADDB = B + A (per the modifier).SUBB = B - A.MULB = B * A.DIVB = B / A. Division by zero kills the process; with.F/.X/.Ithe other field is still written if its divisor is not zero.MODB = B mod A. Same zero rule asDIV.JMPJump to the A-pointer.JMZJump to A if the tested B field(s) are zero. With.F/.X/.Iboth fields must be zero.JMNJump to A if the tested field(s) are not zero. With.F/.X/.I: if either is not zero.DJNDecrement the tested field(s) of B, then jump to A if the result is not zero. Classic loop counter.SPLAdd a new process at the A-pointer, queued after the current processes. The current process continues at the next instruction. Up toMAXPROCESSES(8000) per warrior; beyond thatSPLdoes nothing.SEQSkip the next instruction if A equals B (per modifier).CMPis a synonym.SNESkip the next instruction if A differs from B.SLTSkip the next instruction if A is less than B (unsigned, 0..7999).LDPLoad from p-space: value at p-space[A-value] is written to the B target.STPStore to p-space: the A value is written to p-space[B-value].NOPDoes nothing (but still evaluates both operands).
All arithmetic is modulo CORESIZE. Numbers in the core are always 0..7999; -1 is stored as 7999.
7. Directives
ORG labelWhere execution starts. Default: the first instruction.END [label]End of source; an optional label acts likeORG.name EQU exprTextual constant; every later use of name is replaced by expr. Can hold an operand with its mode (EQU #7) or even an opcode.FOR n ... ROFRepeats the block n times. A label on theFORline, or on the line just before it, is the counter (1-based).&counterinside the block expands to the two-digit counter, solabel&imakeslabel01,label02, ...FOR 0blocks are skipped, handy as long comments.PIN nP-space identity. Two warriors with the samePINshare their p-space (except cell 0).
ORG loop
loop FOR 3
MOV.I #0, &loop
ROF
8. Expressions
Operators, highest priority first: unary - + !, then * / % (integer, truncating), then + -, then comparisons == != < > <= >=, then && and ||. Parentheses are allowed. Comparisons yield 1 or 0.
Predefined constants: CORESIZE, MAXCYCLES, MAXPROCESSES, MAXLENGTH, MINDISTANCE, PSPACESIZE, ROUNDS, WARRIORS (2), VERSION (92), CURLINE (index of the current instruction).
A label used in an expression is its distance from the current instruction, so label+1 is the cell after label, and start-target is a plain number of cells.
9. P-space
Each warrior has a private array of PSPACESIZE (500) cells that survives between rounds of a match. Indices wrap. Cell 0 is special and always private: at the start of each round it holds the previous result, 0 if the warrior died, otherwise the number of surviving warriors (1 = win, 2 = tie). In the first round it holds CORESIZE-1.
LDP.AB #0, x loads that result into the B-field of x. STP.B x, #1 stores the B-field of x into cell 1. A warrior can use this to switch strategy after a loss.
10. Match rules
- Core size 8000, max cycles 80000, max processes 8000, max length 100, min distance 100, p-space 500.
- A match is N rounds. Start positions come from the match seed and the round number; the same seed replays the same match.
- Scoring: every survivor of a round gets (W*W-1)/S points, W = number of warriors, S = survivors; the others get 0. With two warriors that is 3 for a win, 1 each for a tie, 0 for a loss.
- Up to 36 warriors can share the core (Settings sets the slot limit); they start at least MINDISTANCE apart and the same bot may take several slots.
- The warrior that executes first alternates every round.
- Test mode (one bot) reports SURVIVED or DIED at
MAXCYCLES.
11. Common patterns
- Imp:
MOV.I #0, 1. Unkillable by bombs, never wins alone. - Imp gate:
JMP 0, <gate. Decrements the cell in front every cycle, turning arriving imps intoMOV.I 0, 0. - Bomber (Dwarf):
ADD,MOV,JMPloop droppingDATs with a step that covers the core. - Scanner: compare cells against zero, bomb what you find.
- Replicator (paper): copy yourself somewhere else with a
MOVloop, thenSPLthere. - SPL bomb:
SPL 0carpets; a warrior that lands on them fills its process queue with useless loops. - Boot: copy the warrior far away and run the copy so the original code is a decoy.