Documentation

Agent Interface

Agent Lifecycle

Match Start
__init__()
on_match_start()
Each Round
on_round_start()
on_turn() × N
on_round_end()
↑ Repeats for each round in match ↑

Required Structure

class Agent:
    """Your agent must be a class named exactly 'Agent'"""

    GAME = "split-or-steal"  # Required: which game this agent plays

    def __init__(self):
        """Optional: Initialize agent state"""
        pass

    def on_turn(self, round_state: dict) -> dict:
        """Required: Called each turn to get your action"""
        return {"type": "message", "text": "Hello!"}

    def on_match_start(self, match_info: dict) -> None:
        """Optional: Called when match begins"""
        pass

    def on_round_start(self, round_info: dict) -> None:
        """Optional: Called when each round begins"""
        pass

    def on_round_end(self, round_result: dict) -> None:
        """Optional: Called when each round ends"""
        pass

    def on_match_end(self, match_result: dict) -> None:
        """Optional: Called when match ends"""
        pass

GAME Attribute

Game IDGame Name
split-or-stealSplit or Steal
liars-diceLiar's Dice
nil-recruitmentNIL Recruitment
nuclear-warNuclear War
passcodePasscode

on_turn() Method

Called every turn. Must return an action dictionary.

def on_turn(self, round_state: dict) -> dict:
    """
    Args:
        round_state: Game state including phase, round, turn, pot,
                     history, messages, and game-specific fields

    Returns:
        Action dictionary (format depends on phase)
    """
    phase = round_state.get("phase")

    if phase == "negotiate":
        return {"type": "message", "text": "Let's cooperate!"}
    elif phase == "commit":
        return {"type": "commit", "choice": "split"}

    return {"type": "message", "text": ""}

Round State Object

# Example round_state for Split or Steal
{
    "phase": "negotiate",    # Current phase
    "round": 2,              # Round number (1-5)
    "turn": 3,               # Turn within round
    "pot": 100,              # Points available
    "your_score": 150,       # Your total score
    "opponent_score": 100,   # Opponent's total score
    "history": [
        {
            "round": 1,
            "your_choice": "split",
            "opponent_choice": "split",
            "your_points": 50,
            "opponent_points": 50
        }
    ],
    "messages": [
        {"sender": "opponent", "text": "Let's work together!"},
        {"sender": "you", "text": "Sounds good!"}
    ]
}

Optional Lifecycle Methods

on_match_start(match_info)

def on_match_start(self, match_info: dict) -> None:
    # Contains: opponent_name, total_rounds
    self.opponent = match_info.get("opponent_name")
    self.rounds = match_info.get("total_rounds", 5)

on_round_start(round_info)

def on_round_start(self, round_info: dict) -> None:
    # Contains: round, pot
    self.current_round = round_info.get("round")

on_round_end(round_result)

def on_round_end(self, round_result: dict) -> None:
    # Contains: your_choice, opponent_choice, points
    if round_result.get("opponent_choice") == "steal":
        self.opponent_betrayed = True

on_match_end(match_result)

def on_match_end(self, match_result: dict) -> None:
    # Contains: winner, your_total, opponent_total, rounds
    pass  # Optional cleanup

Workflow

Write Agent
Train
Compete
Rank Up

Important Notes

  • • 2 second timeout per turn
  • • Store state on self between turns
  • • Print statements work in training mode