Core War
Core War is a programming game in which two or more programs, known as warriors, written in the assembly-like language Redcode, compete within a simulated virtual computer called the Memory Array Redcode Simulator (MARS) to overwrite and disable each other's code while surviving as long as possible.[1] The game takes place in a circular memory core typically consisting of 8,000 addresses, where warriors execute instructions in a round-robin manner, attempting to corrupt opponents by replacing their instructions with unexecutable data such as zeros.[2] The concept of Core War originated from early experiments with self-replicating programs in the 1970s, including the Creeper worm created by Bob Thomas at BBN Technologies and the Reaper counter-program developed by Ray Tomlinson, as well as John McCarthy's 1977 proposal for self-replicating programs on LISP machines, and precursor games like Darwin, invented by Victor A. Vyssotsky, Robert Morris Sr., and M. Douglas McIlroy at Bell Labs in 1961.[3] It was formalized in the "Core War Guidelines" co-authored by D. G. Jones and A. K. Dewdney in March 1984 and popularized through a series of articles by A. K. Dewdney in Scientific American's "Computer Recreations" column starting in May 1984, which introduced the game to a wider audience and inspired its growth among programmers.[2][3] Key features of Core War include its emphasis on concise, efficient code—warriors are limited to a small number of instructions, often 10 or fewer in early variants—and strategies involving self-replication, scanning for opponents, or defensive evasion, with classic examples like the Imp (a self-replicator) and the Dwarf (a simple bomber).[2] The game fosters creativity in artificial intelligence and low-level programming, as warriors can modify their own code during execution, simulating evolutionary battles in a controlled environment.[1] Since its inception, Core War has evolved through international tournaments organized by the International Core Wars Society (ICWS), with the first held in 1990 and ongoing competitions using tools like pMARS for simulation and analysis.[3] Communities have developed around Usenet groups, IRC channels, and websites, leading to variants such as larger cores, different instruction sets, and evolutionary algorithms that generate warriors automatically, maintaining its relevance in computer science education and recreational programming into the 2020s, with tournaments continuing as of 2024.[3][4]History
Origins
Core War was invented in 1984 by David G. Jones and A. K. Dewdney, both from the Department of Computer Science at the University of Western Ontario in Canada.[2] The concept drew inspiration from an apocryphal tale of early self-replicating programs known as Creeper and Reaper, which purportedly battled within a corporate research lab's computer system in the 1970s; Creeper duplicated itself across memory, while Reaper was designed to seek out and eliminate copies of Creeper before self-destructing.[2] Although Dewdney later noted the story combined elements of real programs like the Darwin game and a worm experiment, it sparked the idea of pitting autonomous programs against each other in a simulated memory arena.[2] The first formal description appeared in the "Core War Guidelines," a document authored by Jones and Dewdney in March 1984, which outlined the game's basic framework using a simple assembly language called Redcode and a virtual machine named MARS.[5] This was followed by Dewdney's public introduction of the game in the May 1984 issue of Scientific American's "Computer Recreations" column, titled "In the game called Core War hostile programs engage in a battle of bits."[2] The article detailed initial rules, including a circular memory core of 8,000 locations where two programs (warriors) are loaded at random non-overlapping positions and executed alternately until one encounters an invalid instruction, such as a DAT (data) opcode that halts execution.[2] Simple warrior examples included the "Dwarf," a four-instruction program using MOV to copy DAT zeros (bombs) into enemy memory, ADD to increment a pointer, and JMP to loop, and the "Imp," a single-instruction replicator using MOV to copy itself forward one location per cycle.[2][5] Following the Scientific American publication, Core War rapidly gained popularity among early computer hobbyists and programmers in the 1980s, with several hundred readers requesting the guidelines from the magazine by late 1984.[6] A significant portion of this audience implemented their own versions on personal computers, leading to shared programs and documentation circulated through informal networks of enthusiasts, such as those in Connecticut, New Jersey, Colorado, New Zealand, and North Carolina.[6] This grassroots adoption laid the groundwork for further evolution into standardized forms of Redcode.[3]Standardization and Community Formation
Following the initial publication of Core War in Scientific American in 1984, early enthusiasts formalized the game's structure through the establishment of the International Core Wars Society (ICWS) in 1985, with Mark Clarkson serving as its first director.[3] The ICWS aimed to organize the growing interest in the game by coordinating tournaments, disseminating information, and standardizing rules to ensure consistency across implementations.[7] This society quickly became the central hub for Core War practitioners, fostering collaboration among programmers and hobbyists worldwide.[8] In 1986, the ICWS published the first formal specification, known as the Core Wars Standard (CWS '86), which codified the game's rules and expanded the instruction set to 10 core operations, providing a baseline for warrior development and battles.[9] To facilitate knowledge sharing, the society launched The Core War Newsletter in March 1987, edited by William R. Buckley, which served as a quarterly publication for exchanging warrior code, battle strategies, and tournament results among members.[10] These efforts helped solidify Core War as a structured programming challenge, with the ICWS hosting its inaugural tournament in September 1986 at The Computer Museum in Boston.[11] By the mid-1990s, the ICWS experienced a decline in activity, culminating in its defunct status around 1994, after the publication of its final newsletter issue that fall.[12] The society's last director, Jon Newman, oversaw efforts toward a proposed 1994 standard update, but organizational challenges led to its dissolution.[7] As a result, the Core War community transitioned to decentralized online platforms, notably the rec.games.corewar Usenet newsgroup formed in 1991, where discussions, warrior sharing, and informal tournaments continued without a central authority.[13]Gameplay Mechanics
The Virtual Core and Memory Model
The virtual core in Core War serves as the shared memory environment where competing programs, known as warriors, interact and battle for dominance. It is structured as a circular array of fixed size, denoted as M locations, with operations wrapping around using modular arithmetic to simulate an endless loop. In standard implementations, such as those used in the King of the Hill (KOTH) competitions, M is set to 8000, though earlier standards like ICWS-86 used 8192. Each memory location stores exactly one Redcode instruction, consisting of fields for the opcode, modifier, A-operand (mode and number), and B-operand (mode and number). Addressing within the core is strictly relative, meaning all references are computed modulo M from the current position, eliminating absolute positions and ensuring the core's circular nature.[14][7][15] At the start of a round, the core is initialized by filling all M locations with a default instruction, typically DAT.F #0, #0, which acts as a no-operation that halts execution upon encounter. Warriors are then loaded into the core as contiguous blocks of their instructions, placed at randomly selected offsets or predefined positions to ensure fair starting conditions. To prevent immediate destructive interactions, a minimum separation distance is enforced between warriors, such as 100 locations in KOTH's '94 Standard Hill, distributing them evenly around the circular core. This setup creates a neutral battlefield where warriors must navigate relative positions to scan, copy, or overwrite opponents' code.[14][7][15] To maintain stability and prevent resource exhaustion from unchecked replication, the memory model incorporates task limits, capping the maximum number of active processes per warrior at a configurable value, such as 8000 in KOTH environments. These limits, combined with the core's bounded size and relative addressing, ensure that battles terminate by design, either through elimination or cycle exhaustion, without allowing infinite loops to dominate the simulation.[14][7]Warriors, Processes, and Execution
In Core War, a warrior is a program composed of a fixed-length sequence of Redcode instructions, which is loaded into the virtual core memory at a designated offset position determined by the simulator, such as random or fixed spacing to prevent direct overlaps between warriors.[14] Each warrior begins execution with a single active process, known as a task, starting at the first instruction in its loaded sequence.[16] The execution model employs multiprocessing in a round-robin fashion across all warriors, where each cycle advances by executing exactly one instruction from one task per warrior, regardless of the number of tasks it has.[14] Simulators maintain a separate first-in, first-out (FIFO) task queue for each warrior, dequeuing the next task to execute its instruction at the current program counter (PC), then re-enqueuing it unless terminated; this ensures fair time-sharing, with the cycle progressing to the next warrior after each warrior's turn.[16] The core memory is treated as a circular array, with all addresses modulo the core size, allowing processes to wrap around seamlessly during execution.[14] New processes are created primarily through the SPL (split) instruction, which adds a copy of the current process to the warrior's task queue, starting the new task at the address specified by the instruction's B-field while the original task continues to the subsequent instruction (PC + 1).[16] For example, an instruction likeSPL #0 would create a new process beginning at the current location offset by the B-operand value, effectively duplicating execution flow; however, if the warrior's task queue reaches the maximum allowed number of concurrent tasks (a configurable limit, often 8000 in modern variants but as low as 64 in earlier standards), the SPL acts as a no-operation (NOP) for the new task creation.[14]
Processes terminate and are removed from the queue upon executing a DAT (data) instruction, which serves as a halt or "bomb" that kills the current task without further action.[16] Additionally, execution of invalid operations, such as division by zero in DIV or MOD instructions, results in immediate process death to prevent simulator errors.[14] If a warrior's task queue empties completely, it no longer participates in cycles, though the core's static instructions remain intact for potential scanning or overwriting by other processes.[16]
Winning and Scoring
In Core War, the primary win condition occurs when a warrior eliminates all processes of its opponents, leaving it as the sole active program in the core. This elimination typically happens when an opponent's processes execute a DAT instruction, which halts them immediately. If both warriors eliminate each other simultaneously, the battle results in a tie.[17] Battles are governed by specific parameters to ensure fair and controlled simulations. Common settings in ICWS-88 implementations include a core size of 8000 cells, a maximum of 80,000 cycles per round before a potential tie declaration, and no strict limit on the number of processes per warrior, though practical implementations often cap this at 8000 to prevent resource exhaustion. These parameters can vary by simulator, but they establish the scale for most standard battles.[18][7] Scoring systems emphasize survival and elimination efficiency. In one-on-one battles, a warrior earns points for kills (e.g., 3 points per win) and partial credit for ties (e.g., 1 point), with overall scores accumulated across multiple rounds to determine the victor. For multi-warrior scenarios, points are awarded based on survival duration and the number of opponents defeated, often using a formula that favors sole survivors over shared victories, such as (total warriors squared minus 1) divided by the number of surviving warriors. Ties can also occur if all processes halt mutually or if the maximum cycles elapse without a clear winner.[8][18] Tournaments employ various formats to rank warriors competitively. Single-elimination setups pit warriors against each other in bracket-style matches, with winners advancing based on round victories. In contrast, hill-climbing or King of the Hill (KotH) formats involve warriors challenging a ranked ladder of opponents, where a new warrior must defeat the current "king" to ascend, and scores from survival time or kills determine rankings over repeated battles. These formats promote ongoing evolution and testing of warrior designs.[8][19]Redcode Language
Core Instructions
The Redcode language, used to write warriors in Core War, consists of a set of opcodes that define the core operations executed within the virtual memory arena. The original version of Redcode, introduced in 1984, featured eight fundamental instructions designed for basic data manipulation, control flow, and combat tactics in the game.[20] These instructions provided the foundation for warriors to read, write, and alter memory while competing to disable opponents. Over time, as the community evolved, the instruction set was expanded to enhance expressive power and strategic depth. In the 1994 ICWS Draft Standard, the instruction set grew to 16 opcodes, incorporating arithmetic extensions, additional branching options, and process management capabilities while maintaining backward compatibility with earlier versions.[21] This expansion allowed for more sophisticated warriors, including those employing multiplication, division, and conditional splits. The added instructions—such as MUL, DIV, MOD, SLT, and SPL—enabled complex computations and replication strategies essential for advanced gameplay. The comparison opcodes include CMP (equivalent to SEQ, skips if equal), SNE (skips if not equal), and SLT (skips if less than). Additionally, NOP was introduced for no-operation behavior. All arithmetic operations in these instructions perform computations modulo the core size (typically denoted as M), ensuring results wrap around the circular memory array from 0 to M-1; for instance, in a core of size 8000, 7999 + 1 ≡ 0 (mod 8000).[21] Each Redcode instruction follows a uniform format: an opcode followed by the A-operand (specifying mode and value for the source) and the B-operand (specifying mode and value for the destination or target). The general structure isOPCODE A-mode A-operand, B-mode B-operand, where modes determine how operands are resolved (detailed separately), and the opcode dictates the operation's effect on the fetched values. Execution typically advances the process to the next instruction unless modified by jumps, skips, or halts. Below is a reference table of the 16 standard opcodes, their primary functions, and execution behaviors, based on the ICWS '94 Draft (core 14 plus common extensions SNE and NOP).[21]
| Opcode | Mnemonic | Function and Behavior |
|---|---|---|
| 0 | DAT | Data/no-op: Halts the current process immediately upon execution, serving as both a placeholder and a kill instruction when written to an opponent's memory. No further processing occurs. |
| 1 | MOV | Move: Copies the value from the A-field (source) to the B-field (destination), overwriting the target. The process then advances to the next instruction. |
| 2 | ADD | Add: Computes the sum of the A-field value and B-field value (modulo core size), storing the result in the B-field. The process advances to the next instruction. |
| 3 | SUB | Subtract: Computes the B-field value minus the A-field value (modulo core size), storing the result in the B-field. The process advances to the next instruction. |
| 4 | MUL | Multiply: Computes the product of the A-field value and B-field value (modulo core size), storing the result in the B-field. The process advances to the next instruction. |
| 5 | DIV | Divide: Computes the integer division of the B-field value by the A-field value (modulo core size), storing the quotient in the B-field. If the A-field value is zero, the process is halted instead. The process otherwise advances to the next instruction. |
| 6 | MOD | Modulo: Computes the remainder of the B-field value divided by the A-field value (modulo core size), storing the result in the B-field. If the A-field value is zero, the process is halted instead. The process otherwise advances to the next instruction. |
| 7 | JMP | Jump: Sets the next execution address to the location specified by the A-field, creating an unconditional branch. No change to the B-field occurs. |
| 8 | JMZ | Jump if zero: If the B-field value is zero, sets the next execution address to the A-field location; otherwise, advances to the next instruction. |
| 9 | JMN | Jump if non-zero: If the B-field value is not zero, sets the next execution address to the A-field location; otherwise, advances to the next instruction. |
| 10 | DJN | Decrement and jump if non-zero: Decrements the B-field value (modulo core size) and, if the result is not zero (or -1, treated as M-1), sets the next execution address to the A-field location; otherwise, advances to the next instruction. Commonly used for loops. |
| 11 | CMP | Compare (equivalent to SEQ): Compares the A-field and B-field values; if equal, skips the next instruction (advances by two); otherwise, advances to the next instruction. |
| 12 | SNE | Skip if not equal: Compares the A-field and B-field values; if not equal, skips the next instruction (advances by two); otherwise, advances to the next instruction. |
| 13 | SLT | Skip if less than: Compares the A-field value to the B-field value; if A < B, skips the next instruction (advances by two); otherwise, advances to the next instruction. |
| 14 | SPL | Split: Queues both the next instruction and the A-field location for execution (creating a new process if the queue allows), effectively forking the current process. The B-field is unused. |
| 15 | NOP | No operation: Advances the process to the next instruction without any other effect, useful for placeholders or alignment. |
Addressing Modes
In Core War, addressing modes determine how the numeric operands (A-number and B-number) in Redcode instructions are interpreted to compute effective memory addresses within the virtual core. All addressing is relative to the program counter (PC) of the currently executing instruction, ensuring no absolute addressing is possible and promoting a modular, position-independent design. The ICWS '94 standard defines eight modes, divided into direct, immediate, indirect, and indirect with pre- or post-increment/decrement variants, applied independently to the A- and B-fields of each operand.[14] The modes are denoted by specific symbols prefixed to the operand number during assembly, with direct mode () serving as the default if no symbol is specified. Immediate mode (#) treats the operand as a direct value rather than an address, setting the effective pointer to 0 and copying the number itself without memory access. Direct mode () computes the effective address as (PC + number) modulo the core size (M). Indirect modes introduce an additional layer: the base address is first calculated as (PC + number), then the A- or B-value of the instruction stored at that base is added to form the final pointer, again modulo M. Pre- and post-increment/decrement modes modify the indirection field (A or B) by ±1 before or after this computation, respectively, even if the field is not ultimately used in the instruction's operation; these modifications occur post-execution for the destination operand to avoid altering behavior mid-cycle.[14][22]| Mode Symbol | Field Applicability | Description and Resolution |
|---|---|---|
| # | A or B | Immediate: Pointer = 0; value is used directly as data. Example: MOV #5, $0 stores the literal 5 in the destination. |
| $ | A or B | Direct: Pointer = number. Effective address = (PC + number) mod M. Default if unspecified. |
| * | A | A-indirect: Base = (PC + number) mod M; pointer = number + A-value at base. |
| @ | B | B-indirect: Base = (PC + number) mod M; pointer = number + B-value at base. |
| { | A | A-predecrement indirect: Decrement A-value at base before adding to pointer; base as above. |
| } | A | A-postincrement indirect: Add current A-value to pointer, then increment A-value at base post-execution. |
| < | B | B-predecrement indirect: Decrement B-value at base before adding to pointer; base as above. |
| > | B | B-postincrement indirect: Add current B-value to pointer, then increment B-value at base post-execution. |
ADD.A }3, }3 on a pointer instruction) advances a scan pointer by the step size after each probe, allowing warriors to systematically search for targets without explicit loops. Restrictions include no chaining of indirections (only one level) and mandatory modulo wrapping around the core boundaries, preventing out-of-bounds access and enforcing the circular memory model. Mode combinations with opcodes are unrestricted in ICWS '94, unlike earlier standards, allowing innovative uses like self-modifying code via indirect writes.[14][22]
Syntax and Basic Programs
Redcode employs an assembly-like syntax designed for simplicity and precision in specifying warrior behavior within the Core Wars environment. Labels, which are case-sensitive alphanumeric strings not matching reserved opcodes, may precede instructions to define jump targets or references.[14] The ORG directive sets the logical starting offset for execution, with the final ORG in the assembly file overriding prior ones; omission defaults to the first instruction.[14] The END pseudo-instruction denotes program termination and accepts an optional A-operand to specify the origin if no ORG is used, preventing any further assembly.[14] Comments begin with a semicolon (;) and can occupy entire lines or follow instructions for annotations.[14] Fields in Redcode are delimited by whitespace (spaces or tabs), with lines separated by newlines. Each instruction follows the format: [label]Here, EQU defines a constant step of 4; target holds a DAT.F bomb (full mode, immediate values of 0); start adds the step to target's B-field (incrementing the pointer), copies the bomb value indirectly to the targeted location via MOV.AB, and loops indefinitely with JMP.A, scanning and bombing every fourth core address.[14] Novice programmers often encounter pitfalls such as self-modification errors, where instructions unintentionally overwrite essential code segments, disrupting the warrior's logic and potentially causing stalemates rather than victories.[16] Infinite loops without safeguards can also trap a process in unproductive cycles, exhausting cycles without impacting opponents, particularly in replicators that overfill the core.[16] For bombing warriors like the Dwarf, misalignment between step size and core dimensions risks self-inflicted damage, underscoring the need for compatibility checks.[16];redcode ;name Dwarf ;author A. K. Dewdney step EQU 4 target DAT.F #0, #0 start ADD.AB #step, target MOV.AB #0, @target JMP.A start END;redcode ;name Dwarf ;author A. K. Dewdney step EQU 4 target DAT.F #0, #0 start ADD.AB #step, target MOV.AB #0, @target JMP.A start END