Skip to content

Commit d590a9a

Browse files
committed
Fix "/" bug in agent naming
1 parent c3a3389 commit d590a9a

2 files changed

Lines changed: 129 additions & 139 deletions

File tree

codeclash/cli/ladder.py

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,17 @@
1919
logger = get_logger("ladder")
2020

2121

22-
def _player_slug(branch_init: str, game_name: str) -> str:
23-
"""Turn a ``human/<...>/<bot>`` init branch into a bare, package-safe player name.
24-
25-
The name is used as an on-disk directory and — in the RoboCode arena — as a Java package name
26-
and robot-selector token (``robots/<name>/``, ``sed s/custom/<name>/``,
27-
``selectedRobots=<name>.MyTank``), so it must contain no slashes. RoboCode additionally reserves
28-
the ``robocode`` package namespace for its engine and its robot classloader refuses to load any
29-
robot whose package starts with it, so a leading path segment equal to the game name (RoboCode
30-
branches are ``human/robocode/<bot>``) is dropped rather than folded into a ``robocode_<bot>``
31-
token that would raise ClassNotFoundException at battle time. Non-RoboCode branches
32-
(``human/<author>/<bot>``, ``human/<bot>``) are unaffected: their leading segment never matches
33-
the game name, so the result is the same ``<author>_<bot>`` slug as before.
22+
def _player_slug(branch_init: str) -> str:
23+
"""Turn a ``human/<author>/<bot>`` init branch into a bare, filesystem-safe player name:
24+
strip the ``human/`` prefix and join the rest with ``_`` (e.g. ``human/aleksiy325/snek-two``
25+
-> ``aleksiy325_snek-two``).
26+
27+
RoboCode also uses this name as a Java *package* (``<name>.MyTank``), which must be a bare
28+
identifier that does not start with the engine's reserved ``robocode`` namespace. The RoboCode
29+
ladder branches are named so the plain slug already satisfies that (``human/robo_code/walls``
30+
-> ``robo_code__walls``), so no game-specific handling is needed here.
3431
"""
35-
parts = [p for p in branch_init.split("/") if p]
36-
if parts and parts[0] == "human":
37-
parts = parts[1:]
38-
if parts and parts[0].lower() == game_name.lower():
39-
parts = parts[1:]
40-
return "_".join(parts)
32+
return branch_init.replace("human/", "").replace("/", "__")
4133

4234

4335
def _resolve_ladder_rules(ladder_rules: dict, rounds: int) -> tuple[int, int]:
@@ -115,17 +107,15 @@ def make(
115107
players = config["players"]
116108
num_players = len(players)
117109

118-
game_name = config["game"]["name"]
119-
120110
# Build one fully independent (deep-copied) config per pair up front so concurrent runs
121111
# never share or mutate the same player/config dicts.
122112
jobs: list[tuple[dict, Path]] = []
123113
for i in range(num_players):
124114
for j in range(i + 1, num_players):
125115
player1 = copy.deepcopy(players[i])
126-
player1["name"] = _player_slug(player1["branch_init"], game_name)
116+
player1["name"] = _player_slug(player1["branch_init"])
127117
player2 = copy.deepcopy(players[j])
128-
player2["name"] = _player_slug(player2["branch_init"], game_name)
118+
player2["name"] = _player_slug(player2["branch_init"])
129119
pvp_config = {**copy.deepcopy(config), "players": [player1, player2]}
130120
vs = f"PvpTournament.{player1['name']}_vs_{player2['name']}".replace("/", "_")
131121
output_dir = LOCAL_LOG_DIR / "ladder" / config["game"]["name"] / vs
@@ -196,7 +186,7 @@ def run(
196186
advanced = False
197187
for idx, opponent in enumerate(ladder):
198188
opponent_rank = len(ladder) - idx
199-
opponent["name"] = _player_slug(opponent["branch_init"], config["game"]["name"])
189+
opponent["name"] = _player_slug(opponent["branch_init"])
200190
if "branch_init" in player and idx > 0:
201191
# After first opponent, remove branch_init so that player continues from previous tournament's codebase
202192
del player["branch_init"]

0 commit comments

Comments
 (0)