1313
1414HALITE_LOG = "sim_{idx}.log"
1515HALITE_HIDDEN_EXEC = ".codeclash_exec"
16+ HALITE_WIN_PATTERN = r"Player\s#(\d+),\s(.*),\scame\sin\srank\s#(\d+)"
1617
1718# Command to be run in each agent's `submission/` folder to compile agent
1819MAP_FILE_TYPE_TO_COMPILE = {
@@ -52,10 +53,11 @@ class HaliteArena(CodeArena):
5253"""
5354 default_args : dict = {}
5455 submission : str = "submission"
56+ executable : str = "./environment/halite"
5557
5658 def __init__ (self , config , ** kwargs ):
5759 super ().__init__ (config , ** kwargs )
58- self .run_cmd_round : str = f"./environment/halite --replaydirectory { self .log_env } "
60+ self .run_cmd_round : str = f"{ self . executable } --replaydirectory { self .log_env } "
5961 for arg , val in self .game_config .get ("args" , self .default_args ).items ():
6062 if isinstance (val , bool ):
6163 if val :
@@ -93,13 +95,18 @@ def execute_round(self, agents: list[Player]):
9395 for future in tqdm (as_completed (futures ), total = len (futures )):
9496 future .result ()
9597
96- def get_results (self , agents : list [Player ], round_num : int , stats : RoundStats ):
98+ def get_results (
99+ self ,
100+ agents : list [Player ],
101+ round_num : int ,
102+ stats : RoundStats ,
103+ pattern : str = HALITE_WIN_PATTERN ,
104+ ):
97105 winners = []
98- pattern = r"Player\s#(\d+),\s(.*),\scame\sin\srank\s#(\d+)"
99106 for idx in range (self .game_config ["sims_per_round" ]):
100107 log_file = self .log_round (round_num ) / HALITE_LOG .format (idx = idx )
101108 with open (log_file ) as f :
102- lines = f .readlines ()[- len (agents ) - 1 :]
109+ lines = f .readlines ()[- len (agents ) - 5 :]
103110 for line in lines :
104111 match = re .search (pattern , line )
105112 if match :
@@ -122,32 +129,47 @@ def get_results(self, agents: list[Player], round_num: int, stats: RoundStats):
122129 if player != RESULT_TIE :
123130 stats .player_stats [player ].score = score
124131
125- def validate_code (self , agent : Player ) -> tuple [bool , str | None ]:
132+ def validate_code (
133+ self ,
134+ agent : Player ,
135+ map_file_type_to_compile : dict = MAP_FILE_TYPE_TO_COMPILE ,
136+ map_file_type_to_run : dict = MAP_FILE_TYPE_TO_RUN ,
137+ ) -> tuple [bool , str | None ]:
126138 # Check that the `submission/` folder exists
127139 exists_output = agent .environment .execute ("test -d submission && echo 'exists'" )["output" ]
128140 if "exists" != exists_output .strip ():
129141 return False , f"Submission folder `{ self .submission } /` does not exist"
130142
131143 # Check that there is a *single* file called "main.<ext>" in the submission folder
132144 # and that <ext> is one of the supported file types
145+ found_main = False
133146 sub_path = Path (agent .environment .config .cwd ) / self .submission
134- ls_output = agent .environment .execute ("ls" , cwd = sub_path )["output" ]
147+ ls_output = agent .environment .execute ("ls" , cwd = sub_path )["output" ]. splitlines ()
135148 main_files = [
136- fname
137- for fname in ls_output .splitlines ()
138- if fname .startswith ("main." ) and Path (fname ).suffix in MAP_FILE_TYPE_TO_RUN
149+ fname for fname in ls_output if fname .startswith ("main." ) and Path (fname ).suffix in map_file_type_to_run
139150 ]
140- supported_exts = "|" . join ( MAP_FILE_TYPE_TO_RUN . keys ())
151+
141152 if len (main_files ) != 1 :
153+ # Check if src/main.rs exists for Rust projects
154+ if "src" in ls_output :
155+ src_ls_output = agent .environment .execute ("ls src" , cwd = sub_path )["output" ].splitlines ()
156+ if "main.rs" in src_ls_output :
157+ main_files = ["src/main.rs" ]
158+ found_main = True
159+ else :
160+ found_main = True
161+
162+ if not found_main :
163+ supported_exts = "|" .join (map_file_type_to_run .keys ())
142164 return (
143165 False ,
144166 f"Exactly one main.[{ supported_exts } ] file must be present in submission, found { len (main_files )} " ,
145167 )
146168 main_ext = Path (main_files [0 ]).suffix
147169
148170 # Check that the submission compiles if necessary
149- if main_ext in MAP_FILE_TYPE_TO_COMPILE :
150- compile_cmd = MAP_FILE_TYPE_TO_COMPILE [main_ext ].format (name = "main" )
171+ if main_ext in map_file_type_to_compile :
172+ compile_cmd = map_file_type_to_compile [main_ext ].format (name = "main" )
151173 try :
152174 compile_response = agent .environment .execute (compile_cmd , timeout = 15 , cwd = sub_path )
153175 except subprocess .TimeoutExpired :
@@ -159,8 +181,8 @@ def validate_code(self, agent: Player) -> tuple[bool, str | None]:
159181 )
160182
161183 # Check that submission runs in competition
162- executable = MAP_FILE_TYPE_TO_RUN [main_ext ].format (path = self .submission , name = "main" )
163- run_cmd = f"./environment/halite { shlex .join ([executable , executable ])} "
184+ executable = map_file_type_to_run [main_ext ].format (path = self .submission , name = "main" )
185+ run_cmd = f"{ self . executable } { shlex .join ([executable , executable ])} "
164186 try :
165187 run_response = agent .environment .execute (run_cmd , timeout = 15 )
166188 except subprocess .TimeoutExpired :
@@ -169,6 +191,6 @@ def validate_code(self, agent: Player) -> tuple[bool, str | None]:
169191 return False , f"Submission failed to run (ran { run_cmd } ): { run_response ['output' ]} "
170192
171193 # Record command to run executable to hidden file
172- executable_comp = MAP_FILE_TYPE_TO_RUN [main_ext ].format (path = f"/{ agent .name } /{ self .submission } " , name = "main" )
194+ executable_comp = map_file_type_to_run [main_ext ].format (path = f"/{ agent .name } /{ self .submission } " , name = "main" )
173195 agent .environment .execute (f'echo "{ executable_comp } " > { HALITE_HIDDEN_EXEC } ' )
174196 return True , None
0 commit comments