Skip to content

Commit c46d9a3

Browse files
committed
Add --keep-containers option
1 parent daa37d5 commit c46d9a3

12 files changed

Lines changed: 52 additions & 26 deletions

File tree

codeclash/games/__init__.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from pathlib import Path
2-
31
from codeclash.games.battlecode.battlecode import BattleCodeGame
42
from codeclash.games.battlesnake.battlesnake import BattleSnakeGame
53
from codeclash.games.corewar.corewar import CoreWarGame
@@ -11,7 +9,7 @@
119

1210

1311
# might consider postponing imports to avoid loading things we don't need
14-
def get_game(config: dict, *, tournament_id: str, local_output_dir: Path) -> CodeGame:
12+
def get_game(config: dict, **kwargs) -> CodeGame:
1513
game = {
1614
x.name: x
1715
for x in [
@@ -26,4 +24,4 @@ def get_game(config: dict, *, tournament_id: str, local_output_dir: Path) -> Cod
2624
}.get(config["game"]["name"])
2725
if game is None:
2826
raise ValueError(f"Unknown game: {config['game']['name']}")
29-
return game(config, tournament_id=tournament_id, local_output_dir=local_output_dir)
27+
return game(config, **kwargs)

codeclash/games/battlecode/battlecode.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import re
2-
from pathlib import Path
32

43
from codeclash.agents.player import Player
54
from codeclash.constants import DIR_WORK, RESULT_TIE
@@ -13,8 +12,8 @@
1312
class BattleCodeGame(CodeGame):
1413
name: str = "BattleCode"
1514

16-
def __init__(self, config, *, tournament_id: str, local_output_dir: Path):
17-
super().__init__(config, tournament_id=tournament_id, local_output_dir=local_output_dir)
15+
def __init__(self, config, **kwargs):
16+
super().__init__(config, **kwargs)
1817
assert len(config["players"]) == 2, "BattleCode is a two-player game"
1918
self.run_cmd_round: str = "python run.py run"
2019
for arg, val in self.game_config.get("args", {}).items():

codeclash/games/battlesnake/battlesnake.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import random
33
import time
44
from concurrent.futures import ThreadPoolExecutor, as_completed
5-
from pathlib import Path
65

76
from tqdm.auto import tqdm
87

@@ -14,8 +13,8 @@
1413
class BattleSnakeGame(CodeGame):
1514
name: str = "BattleSnake"
1615

17-
def __init__(self, config, *, tournament_id: str, local_output_dir: Path):
18-
super().__init__(config, tournament_id=tournament_id, local_output_dir=local_output_dir)
16+
def __init__(self, config, **kwargs):
17+
super().__init__(config, **kwargs)
1918
self.run_cmd_round: str = "./battlesnake play"
2019
for arg, val in self.game_config.get("args", {}).items():
2120
if isinstance(val, bool):

codeclash/games/corewar/corewar.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import re
22
import shlex
3-
from pathlib import Path
43

54
from codeclash.agents.player import Player
65
from codeclash.games.game import CodeGame, RoundStats
@@ -12,8 +11,8 @@
1211
class CoreWarGame(CodeGame):
1312
name: str = "CoreWar"
1413

15-
def __init__(self, config, *, tournament_id: str, local_output_dir: Path):
16-
super().__init__(config, tournament_id=tournament_id, local_output_dir=local_output_dir)
14+
def __init__(self, config, **kwargs):
15+
super().__init__(config, **kwargs)
1716
self.run_cmd_round: str = "./src/pmars"
1817
for arg, val in self.game_config.get("args", {}).items():
1918
if isinstance(val, bool):

codeclash/games/game.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def to_dict(self) -> dict[str, Any]:
6161
class CodeGame(ABC):
6262
name: str
6363

64-
def __init__(self, config: dict, *, tournament_id: str, local_output_dir: Path):
64+
def __init__(self, config: dict, *, tournament_id: str, local_output_dir: Path, keep_containers: bool = False):
6565
"""The CodeGame class is responsible for running games, i.e., taking a list of code
6666
from different agents/players and running them against each other.
6767
It also provides the environments for the game and agents to run in.
@@ -74,11 +74,13 @@ def __init__(self, config: dict, *, tournament_id: str, local_output_dir: Path):
7474
config: The overall config for the tournament.
7575
tournament_id: The id of the tournament.
7676
local_output_dir: The host/local directory to write logs to.
77+
keep_containers: Do not remove containers after games/agent finish.
7778
"""
7879
self.url_gh: str = f"git@github.com:{GH_ORG}/{self.name}.git"
7980
self.artifacts: list[Path] = []
8081
"""Artifact objects that we might want to clean up after the game."""
8182
self.config: dict = config
83+
self._keep_containers: bool = keep_containers
8284
self._metadata: dict = {
8385
"name": self.name,
8486
"config": self.config["game"],
@@ -156,6 +158,10 @@ def log_round(self, round_num: int) -> Path:
156158
def get_environment(self, branch_name: str | None = None) -> DockerEnvironment:
157159
"""Get docker container ID with the game code installed."""
158160
self.build_image()
161+
if not self._keep_containers:
162+
run_args = ["--rm"]
163+
else:
164+
run_args = []
159165
environment = DockerEnvironment(
160166
image=self.image_name,
161167
cwd=str(DIR_WORK),
@@ -169,6 +175,7 @@ def get_environment(self, branch_name: str | None = None) -> DockerEnvironment:
169175
},
170176
container_timeout="3h",
171177
logger=self.logger,
178+
run_args=run_args,
172179
)
173180
# Logger setting will likely not take effect for initial container creation logs
174181
environment.logger = get_logger("environment", emoji="🪴")

codeclash/games/huskybench/huskybench.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import re
2-
from pathlib import Path
32

43
from codeclash.agents.player import Player
54
from codeclash.games.game import CodeGame, RoundStats
@@ -14,8 +13,8 @@
1413
class HuskyBenchGame(CodeGame):
1514
name: str = "HuskyBench"
1615

17-
def __init__(self, config, *, tournament_id: str, local_output_dir: Path):
18-
super().__init__(config, tournament_id=tournament_id, local_output_dir=local_output_dir)
16+
def __init__(self, config, **kwargs):
17+
super().__init__(config, **kwargs)
1918
self.num_players: int = len(config["players"])
2019
self.run_cmd_round: str = (
2120
f"python engine/main.py --port {HB_PORT} --players {self.num_players} "

codeclash/games/robocode/robocode.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
class RoboCodeGame(CodeGame):
1414
name: str = "RoboCode"
1515

16-
def __init__(self, config, *, tournament_id: str, local_output_dir: Path):
17-
super().__init__(config, tournament_id=tournament_id, local_output_dir=local_output_dir)
16+
def __init__(self, config, **kwargs):
17+
super().__init__(config, **kwargs)
1818
self.run_cmd_round: str = "./robocode.sh"
1919
for arg, val in self.game_config.get("args", {}).items():
2020
if isinstance(val, bool):

codeclash/games/robotrumble/robotrumble.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import shlex
22
from collections import Counter
33
from concurrent.futures import ThreadPoolExecutor, as_completed
4-
from pathlib import Path
54

65
from tqdm.auto import tqdm
76

@@ -13,8 +12,8 @@
1312
class RobotRumbleGame(CodeGame):
1413
name: str = "RobotRumble"
1514

16-
def __init__(self, config, *, tournament_id: str, local_output_dir: Path):
17-
super().__init__(config, tournament_id=tournament_id, local_output_dir=local_output_dir)
15+
def __init__(self, config, **kwargs):
16+
super().__init__(config, **kwargs)
1817
assert len(config["players"]) == 2, "RobotRumble is a two-player game"
1918
self.run_cmd_round: str = "./rumblebot run term"
2019

codeclash/tournaments/pvp.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,22 @@
1717

1818

1919
class PvpTournament(AbstractTournament):
20-
def __init__(self, config: dict, *, output_dir: Path, cleanup: bool = False, push: bool = False):
20+
def __init__(
21+
self,
22+
config: dict,
23+
*,
24+
output_dir: Path,
25+
cleanup: bool = False,
26+
push: bool = False,
27+
keep_containers: bool = False,
28+
):
2129
super().__init__(config, name="PvpTournament", output_dir=output_dir)
2230
self.cleanup_on_end = cleanup
2331
self.game: CodeGame = get_game(
2432
self.config,
2533
tournament_id=self.tournament_id,
2634
local_output_dir=self.local_output_dir,
35+
keep_containers=keep_containers,
2736
)
2837
self.agents: list[Player] = []
2938
for agent_conf in self.config["players"]:

codeclash/tournaments/single_player.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@
1919

2020

2121
class SinglePlayerTraining(AbstractTournament):
22-
def __init__(self, config: dict, *, output_dir: Path, cleanup: bool = False):
22+
def __init__(self, config: dict, *, output_dir: Path, cleanup: bool = False, keep_containers: bool = False):
2323
super().__init__(config, name="SinglePlayerTraining", output_dir=output_dir)
2424
self.cleanup_on_end = cleanup
2525
self.game: CodeGame = get_game(
2626
self.config,
2727
tournament_id=self.tournament_id,
2828
local_output_dir=self.local_output_dir,
29+
keep_containers=keep_containers,
2930
)
3031
self.agent: Player = self.get_agent(self.config["player"], round=1)
3132
mirror_agent_config = copy.deepcopy(self.config["player"])

0 commit comments

Comments
 (0)