This is an adaption of Core War, a programming KOTH dating back to the 20th century. To be more specific, it is using an incredibly simplified instruction set primarily based off of the original proposal.
Background
In Core War, there are two programs battling for control over the computer. The goal of each program is to win by locating and terminating the opposing program.
The battle takes place within the main memory of the computer. This memory is called the Core, and it contains 8192 addresses. When the battle starts, the code for each competitor (called a warrior) is placed in a random chunk of memory. Program execution alternates between warriors, performing one instruction of each. Each instruction is capable of modifying a part of the Core, leading to the possibility of self-modifying programs.
The goal is to terminate the opposing program. A program terminates when it attempts to execute an invalid instruction, which is any DAT
instruction.
The Instruction Set
Each program consists of a series of low-level instructions, each of which takes two fields, called the A and B fields.
This instruction set draws heavily from the original spec. The main changes are 1) clarification on adding/subtracting commands, and 2) a change of the #
addressing mode to allow it to be used anywhere. Most full versions of Core Wars have over 20 opcodes, 8 addressing modes, and a set of "instruction modifiers."
Opcodes
Each instruction must have one of seven different opcodes.
DAT A B
- (data) - This simply holds the numbersA
andB
. Importantly, a process dies when it attempts to execute a DAT instruction.MOV A B
- (move) - This moves the contents of memory locationA
to memory locationB
. Here is a demonstration of before-and-after:MOV 2 1 ADD @4 #5 JMP #1 -1
MOV 2 1 JMP #1 -1 JMP #1 -1
ADD A B
- (add) - This adds the contents of memory locationA
to memory locationB
. The two first fields of both are added, and the second fields are added.ADD 2 1 MOV @4 #5 JMP #1 -1
ADD 2 1 MOV @5 #4 JMP #1 -1
SUB A B
- (subtract) - This subtracts the contents of memory locationA
from (and stores the result into) memory locationB
.SUB 2 1 MOV @4 #5 JMP #1 -1
SUB 2 1 MOV @3 #6 JMP #1 -1
JMP A B
- (jump) - Jump to locationA
, which will be executed next cycle.B
must be a number but does nothing (you can use it to store information, though).JMP 2 1337 ADD 1 2 ADD 2 3
The jump means that
ADD 2 3
will be executed next cycle.JMZ A B
- (jump if zero) - If both fields of lineB
are 0, then the program jumps to locationA
.JMZ 2 1 SUB 0 @0 DAT 23 45
Since the two fields of instruction 1 are 0, the DAT command will be executed next turn, leading to imminent death.
CMP A B
- (compare and skip if not equal) - If the fields in instructionsA
andB
are not equal, skip the next instruction.CMP #1 2 ADD 2 #3 SUB @2 3
Since the two fields of instructions 1 and 2 are equal in value, the ADD command is not skipped and is executed next turn.
When two instructions are added/subtracted, the two fields (A and B) are added/subtracted pair-wise. The addressing mode and opcode are not changed.
Addressing Modes
There are three kinds of addressing modes. Each of the two fields of an instruction has one of these three addressing modes.
Immediate
#X
-X
is the line to be used directly in computation. For example,#0
is the first line of the program. Negative lines refer to lines in the core before the start of program.... //just a space-filler ... ADD #3 #4 DAT 0 1 DAT 2 4
This will add the first of the two DAT lines to the second, since those are in lines 3 and 4, respectively. You would not want to use this code, however, because the DAT will kill your bot on the next cycle.
Relative
X
- The numberX
represents the location of a target memory address, relative to the current address. The number at this location is used in computation. If line#35
is being executed and contains-5
, then line#30
is used.... //just a space-filler ... ADD 2 1 DAT 0 1 DAT 2 4
This will add the second DAT line to the first.
Indirect
@X
- The numberX
represent a relative address. The contents at that location are temporarily added to the number X to form a new relative address, from which the number is retrieved. If line#35
is being executed, and its second field is@4
, and the second field of line#39
contains the number-7
, then line#32
is used.... //just a space-filler ... ADD @1 @1 DAT 0 1 DAT 2 4
This will add the first DAT to the second, but in a more convoluted way. The first field is @1, which gets the data from that relative address, which is the first field of the first DAT, a 0. This is interpreted as a second relative address from that location, so 1+0=1 gives the total offset from the original instruction. For the second field, @1 gets the value from that relative address (the 1 in the second field of the first DAT) and adds it to itself in the same way. The total offset is then 1+1=2. So, this instruction is executed similarly to
ADD 1 2
.
Each program can contain up to 64 instructions.
When a round starts, the two programs are placed randomly in a memory bank with 8192 locations. The instruction pointer for each program starts at the beginning of the program and is incremented after each execution cycle. The program dies once its instruction pointer attempts to execute a DAT
instruction.
Parameters of the Core
The core size is 8192, with a timeout of 8192*8 = 65536 ticks. The core is cyclic, so writing to address 8195 is the same as writing to address 3. All unused addresses are initialized to DAT #0 #0
.
Each competitor must not be longer than 64 lines. Integers will be stored as 32-bit signed integers.
Parsing
In order to make programming easier for competitors, I will add a line-label feature to the parser. Any words that occur on a line before an opcode will be interpreted as line labels. For example, tree mov 4 6
has the line label tree
. If, anywhere in the program, there is a field that contains tree
#tree
or @tree
, a number will be substituted. Also, capitalization is ignored.
Here is a example of how line labels are substituted:
labelA add labelB @labelC
labelB add #labelC labelC
labelC sub labelA @labelB
Here, labels A, B, and C are on lines 0, 1, and 2. Instances of #label
will be substituted with the line number of the label. Instances of label
or @label
are substituted with the relative location of the label. Addressing modes are preserved.
ADD 1 @2
ADD #2 1
SUB -2 @-1
Scoring
For each pair of contestants, every possible battle is performed. Since the outcome of a battle depends on the relative offsets of the two programs, every possible offset (about 8000 of them) is tried. Furthermore, each program has a chance to move first in each offset. The program that wins the majority of these offsets is the winner of the pair.
For each pair-up that a warrior wins, it is awarded 2 points. For each tie, a warrior is awarded 1 point.
You are allowed to submit more than one warrior. The typical rules for multiple submissions apply, such as no tag-teaming, no cooperating, no king-making, etc. There's not really any room for this in Core War anyways, so it shouldn't be a big deal.
The Controller
The code for the controller, along with two easy example bots, is located here. Since this competition (when run using the official settings) is completely deterministic, the leaderboard you create will be the exact same as the official leaderboard.
Example Bot
Here is an example bot that demonstrates some features of the language.
main mov bomb #-1
add @main main
jmp #main 0
bomb dat 0 -1
This bot operates by slowly erasing all other memory in the core by replacing it with a "bomb." Since the bomb is a DAT
instruction, any program which reaches a bomb will be destroyed.
There are two line labels, "main" and "bomb" which serve to replace numbers. After preprocessing, the program looks like this:
MOV 3 #-1
ADD @-1 -1
JMP #0 0
DAT 0 -1
The first line copies the bomb to the line immediately above the program. The next line adds the value of the bomb (0 -1
) to the move command, and it also demonstrates a use of the @
addressing mode. This addition causes the move command to point to a new target. The next command unconditionally jumps back to the start of the program.
Current Leaderboard
24 - Turbo
22 - DwarvenEngineer
20 - HanShotFirst
18 - Dwarf
14 - ScanBomber
10 - Paranoid
10 - FirstTimer
10 - Janitor
10 - Evolved
6 - EasterBunny
6 - CopyPasta
4 - Imp
2 - Slug
Pairwise Results:
Dwarf > Imp
CopyPasta > Imp
Evolved > Imp
FirstTimer > Imp
Imp > Janitor
Imp > ScanBomber
Slug > Imp
DwarvenEngineer > Imp
HanShotFirst > Imp
Turbo > Imp
EasterBunny > Imp
Paranoid > Imp
Dwarf > CopyPasta
Dwarf > Evolved
Dwarf > FirstTimer
Dwarf > Janitor
Dwarf > ScanBomber
Dwarf > Slug
DwarvenEngineer > Dwarf
HanShotFirst > Dwarf
Turbo > Dwarf
Dwarf > EasterBunny
Dwarf > Paranoid
Evolved > CopyPasta
FirstTimer > CopyPasta
Janitor > CopyPasta
ScanBomber > CopyPasta
CopyPasta > Slug
DwarvenEngineer > CopyPasta
HanShotFirst > CopyPasta
Turbo > CopyPasta
CopyPasta > EasterBunny
Paranoid > CopyPasta
Evolved > FirstTimer
Evolved > Janitor
ScanBomber > Evolved
Evolved > Slug
DwarvenEngineer > Evolved
HanShotFirst > Evolved
Turbo > Evolved
EasterBunny > Evolved
Paranoid > Evolved
Janitor > FirstTimer
ScanBomber > FirstTimer
FirstTimer > Slug
DwarvenEngineer > FirstTimer
HanShotFirst > FirstTimer
Turbo > FirstTimer
FirstTimer > EasterBunny
FirstTimer > Paranoid
ScanBomber > Janitor
Janitor > Slug
DwarvenEngineer > Janitor
HanShotFirst > Janitor
Turbo > Janitor
Janitor > EasterBunny
Janitor > Paranoid
ScanBomber > Slug
DwarvenEngineer > ScanBomber
HanShotFirst > ScanBomber
Turbo > ScanBomber
ScanBomber > EasterBunny
ScanBomber > Paranoid
DwarvenEngineer > Slug
HanShotFirst > Slug
Turbo > Slug
EasterBunny > Slug
Paranoid > Slug
DwarvenEngineer > HanShotFirst
Turbo > DwarvenEngineer
DwarvenEngineer > EasterBunny
DwarvenEngineer > Paranoid
Turbo > HanShotFirst
HanShotFirst > EasterBunny
HanShotFirst > Paranoid
Turbo > EasterBunny
Turbo > Paranoid
Paranoid > EasterBunny
The latest update (new versions of Turbo and Paranoid) took about 5 minutes to run on an old laptop. I would like to thank Ilmari Karonen for his improvements to the controller. If you have a local copy of the controller, you should update your files.