| 13 | |
| 14 | |
| 15 | class BridgeArena(CodeArena): |
| 16 | name: str = "Bridge" |
| 17 | submission: str = "bridge_agent.py" |
| 18 | description: str = """Bridge is a 4-player trick-taking card game played in teams. |
| 19 | |
| 20 | Teams: North/South (positions 0/2) vs East/West (positions 1/3) |
| 21 | |
| 22 | Your bot (bridge_agent.py) must implement these functions: |
| 23 | - get_bid(game_state) -> str: Make bidding decisions, return bid string like "1H", "2NT", "PASS" |
| 24 | - play_card(game_state) -> str: Play a card, return card string like "AS", "7H" |
| 25 | |
| 26 | game_state is a dict containing: |
| 27 | - position: Your position (0=North, 1=East, 2=South, 3=West) |
| 28 | - hand: List of cards in your hand (e.g., ["AS", "KH", "7D"]) |
| 29 | - bids: List of previous bids |
| 30 | - legal_bids: List of legal bids you can make (during bidding) |
| 31 | - legal_cards: List of legal cards you can play (during playing) |
| 32 | - current_trick: Cards played so far in current trick |
| 33 | - contract: The current contract (if bidding is complete) |
| 34 | """ |
| 35 | default_args: dict = { |
| 36 | "sims_per_round": 10, |
| 37 | } |
| 38 | |
| 39 | def __init__(self, config, **kwargs): |
| 40 | # Validate player count before initializing (to avoid Docker build on invalid config) |
| 41 | num_players = len(config.get("players", [])) |
| 42 | if num_players != 4: |
| 43 | raise ValueError(f"Bridge requires exactly 4 players, got {num_players}") |
| 44 | super().__init__(config, **kwargs) |
| 45 | self.run_cmd = "python3 /workspace/run_game.py" |
| 46 | |
| 47 | def validate_code(self, agent: Player) -> tuple[bool, str | None]: |
| 48 | """Validate agent code has required functions.""" |
| 49 | if self.submission not in agent.environment.execute("ls")["output"]: |
| 50 | return False, f"No {self.submission} file found in root directory" |
| 51 | |
| 52 | content = agent.environment.execute(f"cat {self.submission}")["output"] |
| 53 | |
| 54 | # Check for required function definitions |
| 55 | required_functions = ["def get_bid(", "def play_card("] |
| 56 | |
| 57 | missing = [] |
| 58 | for func in required_functions: |
| 59 | if func not in content: |
| 60 | missing.append(func) |
| 61 | |
| 62 | if missing: |
| 63 | return False, f"Missing required functions: {', '.join(missing)}" |
| 64 | |
| 65 | return True, None |
| 66 | |
| 67 | def _run_single_simulation(self, agents: list[Player], idx: int, cmd: str): |
| 68 | """Run a single Bridge game simulation.""" |
| 69 | full_cmd = f"{cmd} -o {self.log_env / f'sim_{idx}.json'}" |
| 70 | |
| 71 | try: |
| 72 | response = self.environment.execute(full_cmd, timeout=60) |
no outgoing calls