A framework for having 5 LLMs play The Resistance: Avalon together.
-
game_engine.py - Game state management
- Role assignment (random)
- Seating order (random)
- Leader rotation
- Log management
- Win condition checking
-
agent_interface.py - LLM prompting system
- Builds prompts for each agent with appropriate context
- Parses responses (votes, quest cards, proposals)
- Manages conversation and private thought logs
- Provides role-specific information to each agent
-
game_loop.py - Main game orchestration
- Runs discussion rounds (3 turns per phase)
- Collects votes and decisions
- Updates game logs
- Handles quest execution
Each quest round follows this structure:
1. Pre-proposal Discussion (3 rounds, all players speak)
↓
2. Each player writes private thoughts + votes
↓
3. Count votes → If rejected, rotate leader and repeat
↓
4. If approved: Post-approval discussion (3 rounds)
↓
5. Quest team members write private thoughts + play quest cards
↓
6. Reveal quest outcome
↓
7. Update logs and check win conditions
When prompting an agent, they receive:
- Official game rules (from Official_Rules.md)
- Their role (Merlin, Assassin, Loyal Servant, Minion)
- Their private knowledge (who they know based on role)
- Public game log (quest history, votes, outcomes)
- Their previous private thoughts (memory of their reasoning)
- Current round's conversation (what's been said so far)
This keeps token usage manageable while providing sufficient context.
├── Official_Rules.md # Game rules
├── game_engine.py # Core game logic
├── agent_interface.py # LLM prompting
├── game_loop.py # Main orchestration
├── requirements.txt # Python dependencies
├── .env.example # Example environment variables
│
└── outputs/ # Game outputs (gitignored)
└── game-YYYYMMDD-HHMMSS/ # Timestamped game directory
├── public_game_log.json # Public information (visible to all)
├── full_game_log.json # Complete information (includes roles)
├── conversation_log.txt # Public discussion only
├── full_conversation_log.txt # Public + private thoughts per message
└── Player*_private_thoughts.txt # Private reasoning per player
Each game run creates a new timestamped directory in outputs/ with all game logs.
The LLMAgent class in game_loop.py is integrated with Anthropic's Claude API using Claude 3 Haiku (the cheapest model for testing).
class LLMAgent:
def __init__(self, name: str, api_key: str = None):
self.name = name
self.client = Anthropic(api_key=api_key)
self.model = "claude-3-haiku-20240307" # Cheapest model
def get_response(self, prompt: str) -> str:
message = self.client.messages.create(
model=self.model,
max_tokens=1024,
messages=[{"role": "user", "content": prompt}]
)
return message.content[0].textTo switch to a different model (e.g., Claude 3.5 Sonnet for better performance), change the self.model variable.
- Install dependencies:
pip install -r requirements.txt- Set up your Anthropic API key:
# Copy the example env file
cp .env.example .env
# Edit .env and add your actual API key
# ANTHROPIC_API_KEY=your-actual-api-key-hereThe .env file is gitignored to keep your API key safe.
python3 game_loop.pyThe game uses Claude 3 Haiku (the cheapest Anthropic model) for testing.
Claude 3 Haiku pricing:
- $0.25 per million input tokens
- $1.25 per million output tokens
A typical 5-player game with 3-5 quest rounds costs approximately $0.10-0.30 depending on conversation length.
-
Token Management: Agents only receive recent conversation + their own past thoughts, not the full game history
-
Information Hiding: Public log vs Full log separation ensures proper game mechanics
-
XML Tags: Used for parsing structured decisions (
<VOTE>,<QUEST_CARD>, etc.) -
Sequential Discussion: Simple rotating speaker order (3 rounds) keeps conversations manageable
-
Private Thoughts: Agents reason about other players before making decisions, creating richer gameplay
Fully Implemented:
- ✅ LLM API integration with Claude 3 Haiku
- ✅ Core game engine with role assignment
- ✅ Discussion rounds with agent conversations
- ✅ Voting system
- ✅ Quest card playing
- ✅ Public and private game logs
- ✅ Player private thoughts and memory
- ✅ Assassination phase (Assassin identifies Merlin after good wins 3 quests)
- ✅ XML-based message separation (private thoughts + public messages)
TODO:
- Implement leader's team proposal via LLM (currently uses placeholder: first N players)
- Add optional roles (Percival, Morgana, Mordred, Oberon)
- Add game replay/analysis tools
- Improve agent reasoning and strategy
After running a game, check the outputs/game-<timestamp>/ directory to see:
public_game_log.json- Game history visible to all playersfull_game_log.json- Complete game history including roles and quest cardsconversation_log.txt- Public messages only (what players see)full_conversation_log.txt- Both private thoughts and public messages for each discussion turnPlayer*_private_thoughts.txt- Each player's reasoning process (voting, quest cards, discussions)