-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathmain.py
More file actions
89 lines (75 loc) · 3.32 KB
/
Copy pathmain.py
File metadata and controls
89 lines (75 loc) · 3.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import subprocess
from codeclash.agents.abstract import Player
from codeclash.games.abstract import CodeGame
from codeclash.utils.environment import copy_file_to_container
class RoboCodeGame(CodeGame):
name: str = "RoboCode"
def __init__(self, config):
super().__init__(config)
self.run_cmd_round: str = "./robocode.sh"
for arg, val in self.config.get("args", {}).items():
if isinstance(val, bool):
if val:
self.run_cmd_round += f" -{arg}"
else:
self.run_cmd_round += f" -{arg} {val}"
def _get_battle_config(self) -> str:
default_battle_config = {
"battle": {
"numRounds": 10,
"gunCoolingRate": 0.1,
"rules": {"inactivityTime": 450, "hideEnemyNames": True},
},
"battleField": {"width": 800, "height": 600},
}
user_battle_config = self.config.get("battle", {})
def merge_dicts(default, user):
for key, value in user.items():
if isinstance(value, dict) and key in default:
merge_dicts(default[key], value)
else:
default[key] = value
merge_dicts(default_battle_config, user_battle_config)
# Turn battle config dict into strings
battle_lines = ["#Battle Properties"]
def dict_to_lines(d, prefix=""):
for key, value in d.items():
if isinstance(value, dict):
dict_to_lines(value, prefix + key + ".")
else:
battle_lines.append(f"robocode.{prefix}{key}={value}")
dict_to_lines(default_battle_config)
return "\n".join(battle_lines)
def determine_winner(self, agents: list[Player]):
response = self.environment.execute(f"head -3 {self.round_log_path} | tail -1")
winner = response["output"].split()[1].rsplit(".", 1)[0]
self.scoreboard.append((self.round, winner))
def execute_round(self, agents: list[Player]):
for agent in agents:
# Copy the agent codebase into the game codebase and compile it
for cmd in [
f"mkdir -p robots/{agent.name}",
f"cp -r /{agent.name}/robots/custom/* robots/{agent.name}/",
f"find robots/{agent.name}/ -name '*.java' -exec sed -i 's/custom/{agent.name}/g' {{}} +",
f'javac -cp "libs/robocode.jar" robots/{agent.name}/*.java',
]:
self.environment.execute(cmd)
# Create .battle file
selected_robots = ",".join([f"{agent.name}.MyTank*" for agent in agents])
battle_file = f"{self.game_id}-round{self.round}.battle"
with open(battle_file, "w") as f:
f.write(
f"""#Battle Properties
{self._get_battle_config()}
robocode.battle.selectedRobots={selected_robots}
"""
)
copy_file_to_container(self.environment, battle_file, f"battles/{battle_file}")
subprocess.run(f"rm -f {battle_file}", shell=True)
# Run battle
cmd = (
f"{self.run_cmd_round} -battle {battle_file} -results {self.round_log_path}"
)
self.logger.info(f"Running command: {cmd}")
response = self.environment.execute(cmd)
assert response["returncode"] == 0, response