| 43 | return int(self.game_config.get("args", {}).get("episodes_per_round", self.game_config["sims_per_round"])) |
| 44 | |
| 45 | def validate_code(self, agent: Player) -> tuple[bool, str | None]: |
| 46 | quoted_submission = shlex.quote(self.submission) |
| 47 | file_check = agent.environment.execute(f"test -f {quoted_submission} && echo exists") |
| 48 | if "exists" not in file_check["output"]: |
| 49 | return False, f"Submission file `{self.submission}` not found in the workspace root" |
| 50 | |
| 51 | content = agent.environment.execute(f"cat {quoted_submission}")["output"] |
| 52 | if not content.strip(): |
| 53 | return False, f"`{self.submission}` is empty" |
| 54 | |
| 55 | syntax_check = agent.environment.execute(f"python -m py_compile {quoted_submission}") |
| 56 | if syntax_check["returncode"] != 0: |
| 57 | return False, f"Python syntax error in `{self.submission}`:\n{syntax_check['output']}" |
| 58 | |
| 59 | validation_timeout = int(self._game_arg("validation_timeout")) |
| 60 | try: |
| 61 | import_check = agent.environment.execute( |
| 62 | "python - <<'PY'\n" |
| 63 | "import importlib.util\n" |
| 64 | f"spec = importlib.util.spec_from_file_location('submission_agent', {self.submission!r})\n" |
| 65 | "module = importlib.util.module_from_spec(spec)\n" |
| 66 | "spec.loader.exec_module(module)\n" |
| 67 | "assert hasattr(module, 'decide'), 'decide function not found'\n" |
| 68 | "assert callable(module.decide), 'decide must be callable'\n" |
| 69 | "result = module.decide([0, 1, 0], {'type': 'discrete', 'n': 11})\n" |
| 70 | "assert result is None or isinstance(result, int), 'decide must return an integer action or None'\n" |
| 71 | "PY", |
| 72 | timeout=validation_timeout, |
| 73 | ) |
| 74 | except subprocess.TimeoutExpired: |
| 75 | return False, f"`decide` validation exceeded {validation_timeout}s timeout" |
| 76 | if import_check["returncode"] != 0: |
| 77 | return False, f"Could not import or call `decide` from `{self.submission}`:\n{import_check['output']}" |
| 78 | |
| 79 | return True, None |
| 80 | |
| 81 | def execute_round(self, agents: list[Player]) -> None: |
| 82 | agent_args = [] |