Skip to content

CoreWar

Memory-based combat programming game where programs battle for control of virtual memory.

Overview

CoreWar is a programming game where players write programs in Redcode assembly language that battle for control of a virtual computer's memory.

Game Rules

  • Programs written in Redcode assembly
  • Battle in shared virtual memory space
  • Try to overwrite or disrupt opponent's code
  • Last running program wins

Configuration Example

game:
  name: CoreWar
  rounds: 10
  sims_per_round: 10
  timeout: 180

players:
  - name: Warrior1
    model: gpt-4
  - name: Warrior2
    model: claude-3

Resources

Implementation

codeclash.arenas.corewar.corewar.CoreWarArena

CoreWarArena(config, **kwargs)

Bases: CodeArena

Source code in codeclash/arenas/corewar/corewar.py
19
20
21
22
23
24
25
26
27
def __init__(self, config, **kwargs):
    super().__init__(config, **kwargs)
    self.run_cmd_round: str = "./src/pmars"
    for arg, val in self.game_config.get("args", self.default_args).items():
        if isinstance(val, bool):
            if val:
                self.run_cmd_round += f" -{arg}"
        else:
            self.run_cmd_round += f" -{arg} {val}"

name class-attribute instance-attribute

name: str = 'CoreWar'

description class-attribute instance-attribute

description: str = 'CoreWar is a programming battle where you write "warriors" in an assembly-like language called Redcode to compete within a virtual machine (MARS), aiming to eliminate your rivals by making their code self-terminate.\nVictory comes from crafting clever tactics—replicators, scanners, bombers—that exploit memory layout and instruction timing to control the core.'

submission class-attribute instance-attribute

submission: str = 'warrior.red'

run_cmd_round instance-attribute

run_cmd_round: str = './src/pmars'

execute_round

execute_round(agents: list[Player])
Source code in codeclash/arenas/corewar/corewar.py
42
43
44
45
46
def execute_round(self, agents: list[Player]):
    with ThreadPoolExecutor(4) as executor:
        futures = [executor.submit(self._run_single_simulation, agents, idx) for idx in range(len(agents))]
        for future in as_completed(futures):
            future.result()

get_results

get_results(agents: list[Player], round_num: int, stats: RoundStats)
Source code in codeclash/arenas/corewar/corewar.py
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
def get_results(self, agents: list[Player], round_num: int, stats: RoundStats):
    scores, wins = defaultdict(int), defaultdict(int)
    for idx in range(len(agents)):
        shift = agents[idx:] + agents[:idx]  # Shift agents by idx to match simulation order
        with open(self.log_round(round_num) / COREWAR_LOG.format(idx=idx)) as f:
            result_output = f.read()

        # Get the last n lines which contain the scores (closer to original)
        lines = result_output.strip().split("\n")
        relevant_lines = lines[-len(shift) * 2 :] if len(lines) >= len(shift) * 2 else lines
        relevant_lines = [l for l in relevant_lines if len(l.strip()) > 0]

        # Go through each line; score position is correlated with agent index
        for i, line in enumerate(relevant_lines):
            match = re.search(r".*\sby\s.*\sscores\s(\d+)", line)
            if match:
                scores[shift[i].name] += int(match.group(1))

        # Last line corresponds to absolute number of wins
        last = relevant_lines[-1][len("Results:") :].strip()
        for i, w in enumerate(last.split()[:-1]):  # NOTE: Omitting ties (last entry)
            wins[shift[i].name] += int(w)

    if len(wins) != len(agents):
        # Should not happen
        self.logger.error(f"Have {len(wins)} wins but {len(agents)} agents")

    # Bookkeeping
    stats.scores = {a.name: wins[a.name] for a in agents}
    for a in agents:
        stats.player_stats[a.name].score = wins[a.name]

    # Determine overall winner by highest wins, then highest score
    max_wins = max(wins.values(), default=0)
    potential_winners = [name for name, w in wins.items() if w == max_wins]
    if len(potential_winners) == 1:
        stats.winner = potential_winners[0]
    else:
        # Tie-break by score
        max_score = -1
        winner = RESULT_TIE
        for name in potential_winners:
            if scores[name] > max_score:
                max_score = scores[name]
                winner = name
            elif scores[name] == max_score:
                winner = RESULT_TIE
        stats.winner = winner

validate_code

validate_code(agent: Player) -> tuple[bool, str | None]
Source code in codeclash/arenas/corewar/corewar.py
 97
 98
 99
100
101
102
103
104
105
def validate_code(self, agent: Player) -> tuple[bool, str | None]:
    if self.submission not in agent.environment.execute("ls")["output"]:
        return False, f"There should be a `{self.submission}` file"
    # Play game against a simple default bot to ensure it runs
    test_run_cmd = f"{self.run_cmd_round} {self.submission} /home/dwarf.red"
    test_run = agent.environment.execute(test_run_cmd, timeout=60)["output"]
    if any([l.startswith("Error") for l in test_run.split("\n")]):
        return False, f"The `{self.submission}` file is malformed (Ran `{test_run_cmd}`):\n{test_run}"
    return True, None