| 125 | """ |
| 126 | create_file_in_container(self.environment, content=battle_content, dest_path=f"battles/{battle_file}") |
| 127 | |
| 128 | # Run battle with results output to file |
| 129 | cmd = f"{self.run_cmd_round} -battle {battle_file}" |
| 130 | self.logger.info(f"Running game: {cmd}") |
| 131 | with ThreadPoolExecutor(self.game_config.get("sim_concurrency", 5)) as executor: |
| 132 | # Submit all simulations to the thread pool |
| 133 | futures = [ |
| 134 | executor.submit(self._run_single_simulation, agents, idx, cmd) |
| 135 | for idx in range(self.game_config.get("sims_per_round", 100) // SIMS_PER_RUN) |
| 136 | ] |
| 137 | |
| 138 | # Collect results as they complete |
| 139 | for future in tqdm(as_completed(futures), total=len(futures)): |
| 140 | future.result() |
| 141 | |
| 142 | def copy_logs_from_env(self, round_num: int) -> None: |
| 143 | """Copy the round's raw logs to the host, then distill each recorded battle's |
| 144 | (enormous, ~30 MB) ``record_{idx}.xml`` into compact per-round ``sim_{n}.jsonl`` files |
| 145 | (the single source for both the agent-facing behavioral trace and the replay viewer), |
| 146 | and pool every recorded game into one readable ``trace.md``. The raw XML is deleted |
| 147 | afterwards so it never bloats the logs shipped to the competing agents.""" |
| 148 | super().copy_logs_from_env(round_num) |
| 149 | round_dir = self.log_round(round_num) |