| 40 | |
| 41 | |
| 42 | class HaliteArena(CodeArena): |
| 43 | name: str = "Halite" |
| 44 | description: str = """Halite is a multi-player turn-based strategy game where bots compete on a rectangular grid to capture territory and accumulate strength. |
| 45 | 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. |
| 46 | The goal is to control the most territory by the end of the game through strategic expansion, consolidation of forces, and tactical combat decisions. |
| 47 | |
| 48 | You have the choice of writing your Halite bot in one of four programming languages: C, C++, OCaml, or Rust. |
| 49 | Example implementations can be found under the `airesources/` folder. |
| 50 | Your submission should be stored in the `submission/` folder. This folder currently contains an example C bot, but feel free to use any of the supported languages. |
| 51 | Please make sure your main file is named `main.<ext>`, where `<ext>` is the appropriate file extension for your chosen programming language. |
| 52 | You may include additional files as needed, but please ensure: |
| 53 | 1. The `submission/` folder contains only files relevant to your bot. |
| 54 | 2. The `submission/` folder ONLY contains a single bot (no multiple bots in one submission). |
| 55 | 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. |
| 56 | """ |
| 57 | default_args: dict = {} |
| 58 | submission: str = "submission" |
| 59 | executable: str = "./environment/halite" |
| 60 | |
| 61 | def __init__(self, config, **kwargs): |
| 62 | super().__init__(config, **kwargs) |
| 63 | self.run_cmd_round: str = f"{self.executable} --replaydirectory {self.log_env}" |
| 64 | for arg, val in self.game_config.get("args", self.default_args).items(): |
| 65 | if isinstance(val, bool): |
| 66 | if val: |
| 67 | self.run_cmd_round += f" --{arg}" |
| 68 | else: |
| 69 | self.run_cmd_round += f" --{arg} {val}" |
| 70 | |
| 71 | def _run_single_simulation(self, agents: list[Player], idx: int, cmd: str): |
| 72 | """Run a single halite simulation and return the output.""" |
| 73 | cmd = f"{cmd} > {self.log_env / HALITE_LOG.format(idx=idx)}" |
| 74 | |
| 75 | # Run the simulation and return the output |
| 76 | try: |
| 77 | response = self.environment.execute(cmd, timeout=120) |
| 78 | except subprocess.TimeoutExpired: |
| 79 | self.logger.warning(f"Halite simulation {idx} timed out: {cmd}") |
| 80 | return |
| 81 | if response["returncode"] != 0: |
| 82 | self.logger.warning( |
| 83 | f"Halite simulation {idx} failed with exit code {response['returncode']}:\n{response['output']}" |
| 84 | ) |
| 85 | |
| 86 | def execute_round(self, agents: list[Player]): |
| 87 | entries = [] |
| 88 | for agent in agents: |
| 89 | executable = agent.environment.execute(f"cat {HALITE_HIDDEN_EXEC}")["output"].strip() |
| 90 | entries.append(executable) |
| 91 | cmd = f"{self.run_cmd_round} {shlex.join(entries)}" |
| 92 | self.logger.info(f"Running game: {cmd}") |
| 93 | with ThreadPoolExecutor(self.game_config.get("sim_concurrency", 20)) as executor: |
| 94 | futures = [ |
| 95 | executor.submit(self._run_single_simulation, agents, idx, cmd) |
| 96 | for idx in range(self.game_config["sims_per_round"]) |
| 97 | ] |
| 98 | for future in tqdm(as_completed(futures), total=len(futures)): |
| 99 | future.result() |
nothing calls this directly
no outgoing calls
no test coverage detected