Skip to content

Commit b5cb57a

Browse files
committed
Make ELO weighted; Remove sims_per_round from BattleCode
1 parent d8834c2 commit b5cb57a

4 files changed

Lines changed: 34 additions & 34 deletions

File tree

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1+
import random
12
import re
23
from pathlib import Path
34
from typing import Any
45

5-
from tqdm.auto import tqdm
6-
76
from codeclash.constants import DIR_WORK, RESULT_TIE
87
from codeclash.games.game import CodeGame, RoundStats
98
from codeclash.utils.environment import copy_from_container
109

10+
BATTLECODE_LOG = "sim.log"
11+
1112

1213
class BattleCodeGame(CodeGame):
1314
name: str = "BattleCode"
@@ -27,27 +28,26 @@ def copy_logs_from_env(self, round_num):
2728
super().copy_logs_from_env(round_num)
2829
copy_from_container(
2930
container=self.environment,
30-
src_path="/testbed/logs",
31-
dest_path=self.log_local / "rounds" / str(round_num),
31+
src_path="/testbed/sim.log",
32+
dest_path=self.log_local / "rounds" / f"sim_{round_num}.log",
3233
)
3334

3435
def get_stats(self, agents: list[Any]) -> RoundStats:
3536
winners = []
36-
for sim_file in [f"logs/sim_{idx}.log" for idx in range(self.game_config["sims_per_round"])]:
37-
ro = self.environment.execute(f"cat {sim_file}")["output"]
38-
lines = ro.strip().split("\n")
39-
# Get the third-to-last line which contains the winner info
40-
winner_line = lines[-3] if len(lines) >= 3 else ""
41-
self.logger.debug(f"Winner line: {winner_line}")
42-
match = re.search(r"\s\((.*)\)\swins\s\(", winner_line)
43-
if match:
44-
winner_key = match.group(1)
45-
self.logger.debug(f"Winner key from match: {winner_key}")
46-
# Map A/B to actual agent names (much closer to original code)
47-
winner = {"A": agents[0].name, "B": agents[1].name}.get(winner_key, RESULT_TIE)
48-
winners.append(winner)
49-
else:
50-
winners.append(RESULT_TIE)
37+
ro = self.environment.execute(f"cat {BATTLECODE_LOG}")["output"]
38+
lines = ro.strip().split("\n")
39+
# Get the third-to-last line which contains the winner info
40+
winner_line = lines[-3] if len(lines) >= 3 else ""
41+
self.logger.debug(f"Winner line: {winner_line}")
42+
match = re.search(r"\s\((.*)\)\swins\s\(", winner_line)
43+
if match:
44+
winner_key = match.group(1)
45+
self.logger.debug(f"Winner key from match: {winner_key}")
46+
# Map A/B to actual agent names (much closer to original code)
47+
winner = {"A": agents[0].name, "B": agents[1].name}.get(winner_key, RESULT_TIE)
48+
winners.append(winner)
49+
else:
50+
winners.append(RESULT_TIE)
5151
return RoundStats(
5252
winner=max(set(winners), key=winners.count),
5353
scores={agent.name: winners.count(agent.name) for agent in agents},
@@ -57,11 +57,10 @@ def execute_round(self, agents: list[Any]):
5757
for agent in agents:
5858
src, dest = f"/{agent.name}/src/mysubmission/", str(DIR_WORK / "src" / agent.name)
5959
self.environment.execute(f"cp -r {src} {dest}")
60+
random.shuffle(agents) # Start position matters in BattleCode! Shuffle to be fair.
6061
args = [f"--p{idx + 1}-dir src --p{idx + 1} {agent.name}" for idx, agent in enumerate(agents)]
6162
cmd = f"{self.run_cmd_round} {' '.join(args)}"
6263
self.logger.info(f"Running game: {cmd}")
6364

64-
self.environment.execute("rm -rf logs; mkdir logs")
65-
for idx in tqdm(range(self.game_config["sims_per_round"])):
66-
response = self.environment.execute(cmd + f" > logs/sim_{idx}.log")
67-
assert response["returncode"] == 0, response
65+
response = self.environment.execute(cmd + f" > {BATTLECODE_LOG}")
66+
assert response["returncode"] == 0, response

codeclash/ratings/elo.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,20 +64,21 @@ def main(log_dir: Path):
6464
f" - {profile.player_id} (Game: {profile.game_id}) - ELO: {profile.rating:.1f} (Games: {profile.games_played})"
6565
)
6666

67-
# Average ELO per player across all games
68-
aggregated_elo = {}
69-
game_counts = {}
67+
# Weighted average ELO per player across all games
68+
weighted_elo = {}
7069
total_games = {}
7170
for profile in player_profiles.values():
7271
pid = profile.player_id
73-
aggregated_elo[pid] = aggregated_elo.get(pid, 0) + profile.rating
74-
game_counts[pid] = game_counts.get(pid, 0) + 1
72+
weighted_elo[pid] = weighted_elo.get(pid, 0) + profile.rating * profile.games_played
7573
total_games[pid] = total_games.get(pid, 0) + profile.games_played
7674

77-
print("\nAverage ELO per player (across all games):")
78-
for pid in aggregated_elo:
79-
avg_elo = aggregated_elo[pid] / game_counts[pid]
80-
print(f" - {pid}: Avg ELO {avg_elo:.1f} (Total Games: {total_games[pid]})")
75+
print("\nWeighted average ELO per player (across all games):")
76+
for pid in weighted_elo:
77+
if total_games[pid] > 0:
78+
avg_elo = weighted_elo[pid] / total_games[pid]
79+
else:
80+
avg_elo = 0.0
81+
print(f" - {pid}: Weighted Avg ELO {avg_elo:.1f} (Total Games: {total_games[pid]})")
8182

8283

8384
if __name__ == "__main__":

configs/pvp/battlecode.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ tournament:
22
rounds: 25
33
game:
44
name: BattleCode
5-
sims_per_round: 5
5+
sims_per_round: 1 # NOTE: Setting to > 1 does nothing for BattleCode, since each round is deterministic
66
args:
77
maps: quack
88
players:

configs/test/dummy_battlecode.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ tournament:
22
rounds: 25
33
game:
44
name: BattleCode
5-
sims_per_round: 2
5+
sims_per_round: 1 # NOTE: Setting to > 1 does nothing for BattleCode, since each round is deterministic
66
args:
77
maps: quack
88
players:

0 commit comments

Comments
 (0)