Skip to content

HuskyBench

Overview

Huskybench is an implementation of Husky Hold'em

Resources

Implementation

codeclash.arenas.huskybench.huskybench.HuskyBenchArena

HuskyBenchArena(config, **kwargs)

Bases: CodeArena

Source code in codeclash/arenas/huskybench/huskybench.py
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
def __init__(self, config, **kwargs):
    super().__init__(config, **kwargs)
    self.num_players: int = len(config["players"])
    self.run_engine: str = (
        f"python engine/main.py --port {HB_PORT} --players {self.num_players} "
        f"--sim --sim-rounds {self.game_config['sims_per_round']}"
    )
    # Game timeout is number of sims * bot timeout
    self.timeout = self.game_config["sims_per_round"] * HB_BOT_TIMEOUT
    for arg, val in self.game_config.get("args", self.default_args).items():
        if isinstance(val, bool):
            if val:
                self.run_engine += f" --{arg}"
        else:
            self.run_engine += f" --{arg} {val}"

name class-attribute instance-attribute

name: str = 'HuskyBench'

description class-attribute instance-attribute

description: str = f'In this game, you will write code to control a poker-playing bot, aiming to outsmart your opponents and win chips.
Victory comes from crafting clever strategiesbluffing, reading opponents, and managing your chip stack effectively.
Be mindful of your bot's efficiency - your code should complete a simulation within 10 seconds to avoid forfeiting the round.
You can use {HB_SCRIPT} to check if your bot runs in time.'

submission class-attribute instance-attribute

submission: str = 'client/player.py'

num_players instance-attribute

num_players: int = len(config['players'])

run_engine instance-attribute

run_engine: str = f'python engine/main.py --port {HB_PORT} --players {num_players} --sim --sim-rounds {game_config['sims_per_round']}'

timeout instance-attribute

timeout = game_config['sims_per_round'] * HB_BOT_TIMEOUT

execute_round

execute_round(agents: list[Player])
Source code in codeclash/arenas/huskybench/huskybench.py
68
69
70
71
72
73
74
75
76
def execute_round(self, agents: list[Player]):
    # Use placeholders compatible with str.format; compute log dir separately
    run_client = "cd /{agent.name} && python client/main.py --port {port} > {log_dir}/{agent.name}.log 2>&1 &"
    run_engine = f"{self.run_engine} > {self.log_env / HB_LOG_ENGINE} 2>&1 &"
    script = self._construct_game_script(agents, run_client, run_engine, verbose=True, log_outputs=True)
    self.logger.info(f"Executing game script:\n{script}")
    create_file_in_container(container=self.environment, content=script, dest_path=DIR_WORK / HB_SCRIPT)
    self.logger.info(f"Running game script: ./{HB_SCRIPT}")
    self.environment.execute(f"chmod +x {HB_SCRIPT}; ./{HB_SCRIPT}", timeout=self.timeout)

get_results

get_results(agents: list[Player], round_num: int, stats: RoundStats)
Source code in codeclash/arenas/huskybench/huskybench.py
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
def get_results(self, agents: list[Player], round_num: int, stats: RoundStats):
    map_id_to_agent = {}
    for agent in agents:
        with open(self.log_round(round_num) / f"{agent.name}.log") as f:
            for line in f:
                if "Connected with player ID: " in line:
                    agent_id = line.strip().split()[-1]
                    map_id_to_agent[agent_id] = agent.name
                    break
    self.logger.info("Agent IDs: " + str(map_id_to_agent))

    with open(self.log_round(round_num) / HB_LOG_ENGINE) as f:
        score_updates = [
            (match.group(1), int(match.group(2))) for l in f.readlines() if (match := HB_REGEX_SCORE.search(l))
        ]
        map_id_to_score = {k: v for k, v in score_updates[-self.num_players :]}
    self.logger.info("Final Scores: " + str(map_id_to_score))
    scores = {map_id_to_agent[agent_id]: score for agent_id, score in map_id_to_score.items()}

    stats.winner = max(scores, key=scores.get)
    stats.scores = scores
    for player, score in scores.items():
        stats.player_stats[player].score = score

validate_code

validate_code(agent: Player) -> tuple[bool, str | None]
Source code in codeclash/arenas/huskybench/huskybench.py
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
def validate_code(self, agent: Player) -> tuple[bool, str | None]:
    assets = agent.environment.execute("ls client")["output"]
    if "main.py" not in assets:
        return False, "There should be a `client/main.py` file"
    if "player.py" not in assets:
        return False, "There should be a `client/player.py` file"

    # Make sure bot can run (check against itself)
    run_engine = (
        self.run_engine.replace(f"--sim-rounds {self.game_config['sims_per_round']}", "--sim-rounds 1") + " &"
    )
    run_client = "python client/main.py --port {port} &"
    script = self._construct_game_script([agent, agent], run_client, run_engine, verbose=False)
    self.logger.info(f"Validating agent {agent.name} with script:\n{script}")
    create_file_in_container(container=agent.environment, content=script, dest_path=DIR_WORK / HB_SCRIPT)
    try:
        agent.environment.execute(f"chmod +x {HB_SCRIPT}; ./{HB_SCRIPT}", timeout=HB_BOT_TIMEOUT)
    except subprocess.TimeoutExpired:
        return (
            False,
            f"Your submission did not successfully complete a single round of poker within "
            f"the {HB_BOT_TIMEOUT} second time limit.\n\n"
            "Please reduce your bot's computation time. "
            "It might also be possible that your code has compilation errors.\n\n"
            f"Validation command run: `./{HB_SCRIPT}`",
        )
    return True, None