Skip to content

Commit d2444cf

Browse files
committed
Add working Halite
1 parent b393675 commit d2444cf

4 files changed

Lines changed: 117 additions & 6 deletions

File tree

codeclash/games/halite/halite.py

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import subprocess
44
from collections import Counter
55
from concurrent.futures import ThreadPoolExecutor, as_completed
6+
from pathlib import Path
67

78
from tqdm.auto import tqdm
89

@@ -11,12 +12,43 @@
1112
from codeclash.games.game import CodeGame, RoundStats
1213

1314
HALITE_LOG = "sim_{idx}.log"
15+
HALITE_SUBMISSION = "submission"
16+
HALITE_HIDDEN_EXEC = ".codeclash_exec"
17+
18+
# Command to be run in each agent's `submission/` folder to compile agent
19+
MAP_FILE_TYPE_TO_COMPILE = {
20+
".cpp": "g++ -std=c++11 {path}.cpp -o {name}.o",
21+
".c": "gcc {path}.c -o {name}.o",
22+
".ml": "ocamlbuild -lib unix {name}.native",
23+
".rs": "cargo build",
24+
}
25+
26+
# Command to be run from `environment/` folder to run competition
27+
MAP_FILE_TYPE_TO_RUN = {
28+
".c": "{path}/{name}.o",
29+
".cpp": "{path}/{name}.o",
30+
".js": "node {path}/{name}.js",
31+
".ml": "{path}/{name}.native",
32+
".py": "python {path}/{name}.py",
33+
".rs": "{path}/target/debug/{name}",
34+
}
1435

1536

1637
class HaliteGame(CodeGame):
1738
name: str = "Halite"
18-
description: str = """Halite is a strategic programming game where players write bots to control ships that gather resources, build structures, and compete for dominance on a grid-based map.
19-
Victory is achieved by outmaneuvering opponents, optimizing resource collection, and strategically expanding your territory"""
39+
description: str = f"""Halite is a multi-player turn-based strategy game where bots compete on a rectangular grid to capture territory and accumulate strength.
40+
Players control pieces that can move across the map to conquer neutral and enemy territory, with each cell providing production that increases the strength of pieces occupying it.
41+
The goal is to control the most territory by the end of the game through strategic expansion, consolidation of forces, and tactical combat decisions.
42+
43+
You have the choice of writing your Halite bot in one of four programming languages: C, C++, OCaml, or Rust.
44+
Example implementations can be found under the `airesources/` folder.
45+
Your submission should be stored in the `{HALITE_SUBMISSION}/` folder. This folder currently contains an example C bot, but feel free to use any of the supported languages.
46+
Please make sure your main file is named `main.<ext>`, where `<ext>` is the appropriate file extension for your chosen programming language.
47+
You may include additional files as needed, but please ensure:
48+
1. The `submission/` folder contains only files relevant to your bot.
49+
2. The `submission/` folder ONLY contains a single bot (no multiple bots in one submission).
50+
3. Your bot can be compiled. See `runGame.sh` under the corresponding `submission/<language>/` folder to see how we will compile and run your bot.
51+
"""
2052
default_args: dict = {}
2153

2254
def __init__(self, config, **kwargs):
@@ -47,10 +79,11 @@ def _run_single_simulation(self, agents: list[Player], idx: int, cmd: str):
4779
def execute_round(self, agents: list[Player]):
4880
entries = []
4981
for agent in agents:
50-
entries.append(f"python /{agent.name}/airesources/Python/RandomBot.py")
82+
executable = agent.environment.execute(f"cat {HALITE_HIDDEN_EXEC}")["output"].strip()
83+
entries.append(executable)
5184
cmd = f"{self.run_cmd_round} {shlex.join(entries)}"
5285
self.logger.info(f"Running game: {cmd}")
53-
with ThreadPoolExecutor(5) as executor:
86+
with ThreadPoolExecutor(20) as executor:
5487
futures = [
5588
executor.submit(self._run_single_simulation, agents, idx, cmd)
5689
for idx in range(self.game_config["sims_per_round"])
@@ -88,4 +121,47 @@ def get_results(self, agents: list[Player], round_num: int, stats: RoundStats):
88121
stats.player_stats[player].score = score
89122

90123
def validate_code(self, agent: Player) -> tuple[bool, str | None]:
124+
# Check that there is a *single* file called "main.<ext>" in the submission folder
125+
# and that <ext> is one of the supported file types
126+
sub_path = Path(agent.environment.config.cwd) / HALITE_SUBMISSION
127+
ls_output = agent.environment.execute("ls", cwd=sub_path)["output"]
128+
main_files = [
129+
fname
130+
for fname in ls_output.splitlines()
131+
if fname.startswith("main.") and Path(fname).suffix in MAP_FILE_TYPE_TO_RUN
132+
]
133+
supported_exts = "|".join(MAP_FILE_TYPE_TO_RUN.keys())
134+
if len(main_files) != 1:
135+
return (
136+
False,
137+
f"Exactly one main.[{supported_exts}] file must be present in submission, found {len(main_files)}",
138+
)
139+
main_ext = Path(main_files[0]).suffix
140+
141+
# Check that the submission compiles if necessary
142+
if main_ext in MAP_FILE_TYPE_TO_COMPILE:
143+
compile_cmd = MAP_FILE_TYPE_TO_COMPILE[main_ext].format(path="main", name="main")
144+
try:
145+
compile_response = agent.environment.execute(compile_cmd, timeout=15, cwd=sub_path)
146+
except subprocess.TimeoutExpired:
147+
return False, f"Compilation failed (ran {compile_cmd} inside {HALITE_SUBMISSION}): timed out"
148+
if compile_response["returncode"] != 0:
149+
return (
150+
False,
151+
f"Compilation failed (ran {compile_cmd} inside {HALITE_SUBMISSION}): {compile_response['output']}",
152+
)
153+
154+
# Check that submission runs in competition
155+
executable = MAP_FILE_TYPE_TO_RUN[main_ext].format(path=HALITE_SUBMISSION, name="main")
156+
run_cmd = f"./environment/halite {shlex.join([executable, executable])}"
157+
try:
158+
run_response = agent.environment.execute(run_cmd, timeout=15)
159+
except subprocess.TimeoutExpired:
160+
return False, f"Submission failed to run (ran {run_cmd}): timed out"
161+
if run_response["returncode"] != 0:
162+
return False, f"Submission failed to run (ran {run_cmd}): {run_response['output']}"
163+
164+
# Record command to run executable to hidden file
165+
executable_comp = MAP_FILE_TYPE_TO_RUN[main_ext].format(path=f"/{agent.name}/{HALITE_SUBMISSION}", name="main")
166+
agent.environment.execute(f'echo "{executable_comp}" > {HALITE_HIDDEN_EXEC}')
91167
return True, None

configs/test/players/2/halite.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
tournament:
2-
rounds: 1
2+
rounds: 3
33
game:
44
name: Halite
5-
sims_per_round: 10
5+
sims_per_round: 250
66
players:
77
- agent: dummy
88
name: p1

configs/test/players/4/halite.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
tournament:
2+
rounds: 3
3+
game:
4+
name: Halite
5+
sims_per_round: 10
6+
players:
7+
- agent: dummy
8+
name: p1
9+
- agent: dummy
10+
name: p2
11+
- agent: dummy
12+
name: p3
13+
- agent: dummy
14+
name: p4
15+
prompts:
16+
game_description: |
17+
You are a software developer ({{player_id}}) competing in an arena called Halite.
18+
In this game, you will write code to control ships that gather resources, build structures, and compete for dominance on a grid-based map.
19+
Victory is achieved by outmaneuvering opponents, optimizing resource collection, and strategically expanding your territory.
20+
21+
The game is played in {{rounds}} rounds. For every round, you (and your competitor) edit program code that controls your bot. This is round {{round}}.
22+
After you and your competitor finish editing your codebases, the game is run automatically.
23+
24+
Your task: improve the bot, located in {{working_dir}}.
25+
{{working_dir}} is your codebase, which contains both your bot and supporting assets.

docker/Halite.Dockerfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ RUN apt-get update \
99
python3-pip python-is-python3 wget git build-essential jq curl locales \
1010
&& rm -rf /var/lib/apt/lists/*
1111

12+
# Install Rust via rustup
13+
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y \
14+
&& . "$HOME/.cargo/env" \
15+
&& echo 'source $HOME/.cargo/env' >> /etc/bash.bashrc
16+
ENV PATH="/root/.cargo/bin:${PATH}"
17+
18+
# Install ocaml
19+
RUN apt-get update && apt-get install -y ocaml ocamlbuild
20+
21+
# Clone Halite repository
1222
ARG GITHUB_TOKEN
1323
RUN git clone https://${GITHUB_TOKEN}@github.com/emagedoc/Halite.git /workspace \
1424
&& cd /workspace \

0 commit comments

Comments
 (0)