Skip to content

BattleCode

Real-time strategy game where robots compete to gather resources and destroy opponents.

Overview

BattleCode is a programming competition where players write Java code to control teams of robots in a real-time strategy game.

Resources

Implementation

codeclash.arenas.battlecode.battlecode.BattleCodeArena

BattleCodeArena(config, **kwargs)

Bases: CodeArena

Source code in codeclash/arenas/battlecode/battlecode.py
26
27
28
29
30
31
32
33
34
35
def __init__(self, config, **kwargs):
    super().__init__(config, **kwargs)
    assert len(config["players"]) == 2, "BattleCode is a two-player game"
    self.run_cmd_round: str = "python run.py run"
    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 = 'BattleCode'

description class-attribute instance-attribute

description: str = 'Battlecode 25 throws you into a real-time strategy showdown where your Python bot pilots a team of specialized robots—Soldiers, Moppers, Splashers—alongside towers that spawn units or generate resources.\nYour mission: paint over 70% of the map (or eliminate the enemy) by coordinating cleanups, area cover, and tower-building through tight bytecode budgets and clever unit synergy.'

default_args class-attribute instance-attribute

default_args: dict = {'maps': 'quack'}

submission class-attribute instance-attribute

submission: str = 'src/mysubmission'

run_cmd_round instance-attribute

run_cmd_round: str = 'python run.py run'

execute_round

execute_round(agents: list[Player])
Source code in codeclash/arenas/battlecode/battlecode.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
def execute_round(self, agents: list[Player]):
    for agent in agents:
        src, dest = f"/{agent.name}/src/{BC_FOLDER}/", str(DIR_WORK / "src" / agent.name)
        self.environment.execute(f"cp -r {src} {dest}")
    args = [f"--p{idx + 1}-dir src --p{idx + 1} {agent.name}" for idx, agent in enumerate(agents)]
    cmd = f"{self.run_cmd_round} {' '.join(args)}"
    self.logger.info(f"Running game: {cmd}")

    with ThreadPoolExecutor(5) as executor:
        # Submit all simulations to the thread pool
        futures = [
            executor.submit(self._run_single_simulation, agents, idx, cmd)
            for idx in range(self.game_config["sims_per_round"])
        ]
        # Collect results as they complete
        for future in tqdm(as_completed(futures), total=len(futures), desc="Simulations"):
            future.result()

get_results

get_results(agents: list[Player], round_num: int, stats: RoundStats)
Source code in codeclash/arenas/battlecode/battlecode.py
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
def get_results(self, agents: list[Player], round_num: int, stats: RoundStats):
    scores = defaultdict(int)
    for idx in range(self.game_config["sims_per_round"]):
        with open(self.log_round(round_num) / BC_LOG.format(idx=idx)) as f:
            lines = f.read().strip().split("\n")
        # Get the third-to-last line which contains the winner info
        assert len(lines) >= 3, "Log file does not contain enough lines to determine winner"
        winner_line = lines[-3]
        reason_line = lines[-2]
        match = re.search(r"\s\((.*)\)\swins\s\(", winner_line)
        if match and reason_line != BC_TIE:
            winner_key = match.group(1)
            # Map A/B to actual agent names (much closer to original code)
            winner = {"A": agents[0].name, "B": agents[1].name}.get(winner_key, RESULT_TIE)
            scores[winner] += 1
        else:
            winner = RESULT_TIE

    stats.winner = max(scores, key=scores.get)
    stats.scores = scores
    for player, score in stats.scores.items():
        stats.player_stats[player].score = score

validate_code

validate_code(agent: Player) -> tuple[bool, str | None]
Source code in codeclash/arenas/battlecode/battlecode.py
90
91
92
93
94
95
96
97
98
def validate_code(self, agent: Player) -> tuple[bool, str | None]:
    if BC_FOLDER not in agent.environment.execute("ls src")["output"]:
        return False, f"There should be a `src/{BC_FOLDER}/` directory"
    if "bot.py" not in agent.environment.execute(f"ls src/{BC_FOLDER}")["output"]:
        return False, f"There should be a `src/{BC_FOLDER}/bot.py` file"
    bot_content = agent.environment.execute(f"cat src/{BC_FOLDER}/bot.py")["output"].splitlines()
    if "def turn():" not in bot_content:
        return False, f"There should be a `turn()` function implemented in `src/{BC_FOLDER}/bot.py`"
    return True, None