@@ -71,27 +71,31 @@ def validate_code(self, agent: Player) -> tuple[bool, str | None]:
7171 if syntax_check ["returncode" ] != 0 :
7272 return False , f"Python syntax error in `{ self .submission } `:\n { syntax_check ['output' ]} "
7373
74- import_check = agent .environment .execute (
75- "python - <<'PY'\n "
76- "import importlib.util\n "
77- f"spec = importlib.util.spec_from_file_location('submission_agent', { self .submission !r} )\n "
78- "module = importlib.util.module_from_spec(spec)\n "
79- "spec.loader.exec_module(module)\n "
80- "assert hasattr(module, 'next_actions'), 'next_actions callable not found'\n "
81- "assert callable(module.next_actions), 'next_actions must be callable'\n "
82- "state = {\n "
83- " 'connection': {'agent_id': 'Alice'},\n "
84- " 'agents': {'Alice': {'unit_ids': ['u0']}},\n "
85- " 'unit_state': {'u0': {'agent_id': 'Alice', 'hp': 3, 'coordinates': [1, 1]}},\n "
86- " 'entities': [],\n "
87- " 'world': {'width': 5, 'height': 5},\n "
88- " 'tick': 0,\n "
89- "}\n "
90- "result = module.next_actions(state)\n "
91- "assert result is None or isinstance(result, dict), 'next_actions must return a dict or None'\n "
92- "PY" ,
93- timeout = int (self ._game_arg ("validation_timeout" )),
94- )
74+ validation_timeout = int (self ._game_arg ("validation_timeout" ))
75+ try :
76+ import_check = agent .environment .execute (
77+ "python - <<'PY'\n "
78+ "import importlib.util\n "
79+ f"spec = importlib.util.spec_from_file_location('submission_agent', { self .submission !r} )\n "
80+ "module = importlib.util.module_from_spec(spec)\n "
81+ "spec.loader.exec_module(module)\n "
82+ "assert hasattr(module, 'next_actions'), 'next_actions callable not found'\n "
83+ "assert callable(module.next_actions), 'next_actions must be callable'\n "
84+ "state = {\n "
85+ " 'connection': {'agent_id': 'Alice'},\n "
86+ " 'agents': {'Alice': {'unit_ids': ['u0']}},\n "
87+ " 'unit_state': {'u0': {'agent_id': 'Alice', 'hp': 3, 'coordinates': [1, 1]}},\n "
88+ " 'entities': [],\n "
89+ " 'world': {'width': 5, 'height': 5},\n "
90+ " 'tick': 0,\n "
91+ "}\n "
92+ "result = module.next_actions(state)\n "
93+ "assert result is None or isinstance(result, dict), 'next_actions must return a dict or None'\n "
94+ "PY" ,
95+ timeout = validation_timeout ,
96+ )
97+ except subprocess .TimeoutExpired :
98+ return False , f"`next_actions` validation exceeded { validation_timeout } s timeout"
9599 if import_check ["returncode" ] != 0 :
96100 return False , f"Could not import or call `next_actions` from `{ self .submission } `:\n { import_check ['output' ]} "
97101
@@ -137,6 +141,17 @@ def get_results(self, agents: list[Player], round_num: int, stats: RoundStats):
137141 for agent in agents :
138142 stats .scores [agent .name ] = CRASH_SCORE
139143 stats .player_stats [agent .name ].score = CRASH_SCORE
144+ stats .details .append (
145+ json .dumps (
146+ {
147+ "player" : agent .name ,
148+ "score" : CRASH_SCORE ,
149+ "status" : "error" ,
150+ "error" : f"missing Bomberland result file: { result_file } " ,
151+ },
152+ sort_keys = True ,
153+ )
154+ )
140155 return
141156
142157 with open (result_file ) as f :
0 commit comments