Spaces:
Configuration error
Configuration error
EZTIME2025 commited on
Commit ·
fb4d798
1
Parent(s): 6016237
promt and scheme eng
Browse files- examples/ai_testing/generate_prompts_from_state.py +285 -0
- examples/ai_testing/my_games/current_state.json +891 -0
- examples/ai_testing/my_games/current_state_optimized.txt +25 -0
- examples/ai_testing/my_games/prompts/a +106 -0
- examples/ai_testing/my_games/prompts/prompt_player_a.json +81 -0
- examples/ai_testing/my_games/prompts/prompt_player_a.txt +94 -0
- examples/ai_testing/my_games/prompts/prompt_player_b.json +68 -0
- examples/ai_testing/my_games/prompts/prompt_player_b.txt +81 -0
- examples/ai_testing/my_games/prompts/prompt_player_c.json +68 -0
- examples/ai_testing/my_games/prompts/prompt_player_c.txt +81 -0
- examples/ai_testing/my_games/test_prompt_format.json +111 -0
- examples/ai_testing/my_games/test_prompt_output.json +0 -792
- examples/ai_testing/play_and_capture.py +20 -0
- examples/ai_testing/play_with_prompts.py +105 -0
- examples/ai_testing/test_json_format.py +192 -0
- promt_format.text +3 -6
- pycatan/ai/prompt_manager.py +7 -2
- pycatan/ai/prompt_templates.py +94 -34
- pycatan/ai/state_filter.py +9 -18
- pycatan/management/game_manager.py +8 -1
- temp_viz_console.py +31 -0
examples/ai_testing/generate_prompts_from_state.py
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Generate AI Prompts from Current Game State
|
| 3 |
+
--------------------------------------------
|
| 4 |
+
Reads the current optimized game state and generates a complete JSON prompt
|
| 5 |
+
for each player in the exact format to send to LLM, including response schema.
|
| 6 |
+
|
| 7 |
+
Run this script DURING a game to see what prompts each AI would receive.
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
import sys
|
| 11 |
+
import json
|
| 12 |
+
from pathlib import Path
|
| 13 |
+
from datetime import datetime
|
| 14 |
+
|
| 15 |
+
# Add parent directory to path
|
| 16 |
+
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
| 17 |
+
|
| 18 |
+
from pycatan.ai.prompt_manager import PromptManager
|
| 19 |
+
from pycatan.ai.config import AIConfig
|
| 20 |
+
from pycatan.ai.prompt_templates import get_response_schema
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def load_current_state():
|
| 24 |
+
"""Load the current optimized game state."""
|
| 25 |
+
state_file = Path('examples/ai_testing/my_games/current_state_optimized.txt')
|
| 26 |
+
|
| 27 |
+
if not state_file.exists():
|
| 28 |
+
print("❌ No current game state found!")
|
| 29 |
+
print(f" Expected: {state_file}")
|
| 30 |
+
print("\n💡 Start a game first:")
|
| 31 |
+
print(" python examples/ai_testing/play_and_capture.py")
|
| 32 |
+
return None
|
| 33 |
+
|
| 34 |
+
with open(state_file, 'r', encoding='utf-8') as f:
|
| 35 |
+
content = f.read()
|
| 36 |
+
|
| 37 |
+
# Find JSON after "JSON:" marker
|
| 38 |
+
json_marker = content.find('JSON:')
|
| 39 |
+
if json_marker != -1:
|
| 40 |
+
json_start = content.find('{', json_marker)
|
| 41 |
+
else:
|
| 42 |
+
json_start = content.find('{')
|
| 43 |
+
|
| 44 |
+
if json_start == -1:
|
| 45 |
+
print("❌ Could not find JSON in state file!")
|
| 46 |
+
return None
|
| 47 |
+
|
| 48 |
+
json_str = content[json_start:].strip()
|
| 49 |
+
|
| 50 |
+
try:
|
| 51 |
+
return json.loads(json_str)
|
| 52 |
+
except json.JSONDecodeError as e:
|
| 53 |
+
print(f"❌ JSON parsing error: {e}")
|
| 54 |
+
return None
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def get_player_colors():
|
| 58 |
+
"""Get color mappings for players (hardcoded for now)."""
|
| 59 |
+
return {
|
| 60 |
+
"a": "Red",
|
| 61 |
+
"b": "Blue",
|
| 62 |
+
"c": "White",
|
| 63 |
+
"d": "Orange"
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def generate_prompt_for_player(player_name, game_state, prompt_manager):
|
| 68 |
+
"""
|
| 69 |
+
Generate a complete prompt for a specific player.
|
| 70 |
+
|
| 71 |
+
Args:
|
| 72 |
+
player_name: Name of the player (e.g., "a", "b", "c")
|
| 73 |
+
game_state: Current game state (optimized format)
|
| 74 |
+
prompt_manager: PromptManager instance
|
| 75 |
+
|
| 76 |
+
Returns:
|
| 77 |
+
Complete prompt dictionary
|
| 78 |
+
"""
|
| 79 |
+
colors = get_player_colors()
|
| 80 |
+
player_color = colors.get(player_name, "Unknown")
|
| 81 |
+
|
| 82 |
+
# Get player index (0-based)
|
| 83 |
+
players = game_state.get("players", {})
|
| 84 |
+
player_names = list(players.keys())
|
| 85 |
+
player_num = player_names.index(player_name) if player_name in player_names else 0
|
| 86 |
+
|
| 87 |
+
# Get current phase and determine what action is needed
|
| 88 |
+
meta = game_state.get("meta", {})
|
| 89 |
+
phase = meta.get("phase", "UNKNOWN")
|
| 90 |
+
current_player = meta.get("curr")
|
| 91 |
+
|
| 92 |
+
# Determine what happened and what to do
|
| 93 |
+
if phase == "SETUP_FIRST_ROUND":
|
| 94 |
+
if current_player == player_name:
|
| 95 |
+
what_happened = "It's your turn in the setup phase. Place your first settlement."
|
| 96 |
+
available_actions = [
|
| 97 |
+
{
|
| 98 |
+
"action": "place_settlement",
|
| 99 |
+
"description": "Place your starting settlement on an available node",
|
| 100 |
+
"example_parameters": {
|
| 101 |
+
"location": "20"
|
| 102 |
+
}
|
| 103 |
+
}
|
| 104 |
+
]
|
| 105 |
+
else:
|
| 106 |
+
what_happened = f"It's {current_player}'s turn to place their first settlement."
|
| 107 |
+
available_actions = None
|
| 108 |
+
elif phase == "SETUP_SECOND_ROUND":
|
| 109 |
+
if current_player == player_name:
|
| 110 |
+
what_happened = "It's your turn in the second setup round. Place your second settlement."
|
| 111 |
+
available_actions = [
|
| 112 |
+
{
|
| 113 |
+
"action": "place_settlement",
|
| 114 |
+
"description": "Place your second starting settlement",
|
| 115 |
+
"example_parameters": {
|
| 116 |
+
"location": "25"
|
| 117 |
+
}
|
| 118 |
+
}
|
| 119 |
+
]
|
| 120 |
+
else:
|
| 121 |
+
what_happened = f"It's {current_player}'s turn to place their second settlement."
|
| 122 |
+
available_actions = None
|
| 123 |
+
else:
|
| 124 |
+
if current_player == player_name:
|
| 125 |
+
what_happened = "It's your turn. Roll the dice to begin."
|
| 126 |
+
available_actions = [
|
| 127 |
+
{
|
| 128 |
+
"action": "roll_dice",
|
| 129 |
+
"description": "Roll the dice to produce resources",
|
| 130 |
+
"example_parameters": {}
|
| 131 |
+
},
|
| 132 |
+
{
|
| 133 |
+
"action": "build_road",
|
| 134 |
+
"description": "Build a road on a specific edge",
|
| 135 |
+
"example_parameters": {"location": "12"}
|
| 136 |
+
},
|
| 137 |
+
{
|
| 138 |
+
"action": "build_settlement",
|
| 139 |
+
"description": "Build a settlement on a specific node",
|
| 140 |
+
"example_parameters": {"location": "45"}
|
| 141 |
+
},
|
| 142 |
+
{
|
| 143 |
+
"action": "buy_development_card",
|
| 144 |
+
"description": "Buy a development card if you have resources",
|
| 145 |
+
"example_parameters": {}
|
| 146 |
+
},
|
| 147 |
+
{
|
| 148 |
+
"action": "wait_for_response",
|
| 149 |
+
"description": "Do nothing on the board, just chat or wait for trade responses",
|
| 150 |
+
"example_parameters": {}
|
| 151 |
+
},
|
| 152 |
+
{
|
| 153 |
+
"action": "end_turn",
|
| 154 |
+
"description": "End your turn when done",
|
| 155 |
+
"example_parameters": {}
|
| 156 |
+
}
|
| 157 |
+
]
|
| 158 |
+
else:
|
| 159 |
+
what_happened = f"It's {current_player}'s turn."
|
| 160 |
+
available_actions = None
|
| 161 |
+
|
| 162 |
+
# Generate the prompt
|
| 163 |
+
prompt = prompt_manager.create_prompt(
|
| 164 |
+
player_num=player_num,
|
| 165 |
+
player_name=player_name,
|
| 166 |
+
player_color=player_color,
|
| 167 |
+
game_state=game_state,
|
| 168 |
+
what_happened=what_happened,
|
| 169 |
+
available_actions=available_actions,
|
| 170 |
+
custom_instructions=f"You are player '{player_name}' ({player_color}). Play strategically to win."
|
| 171 |
+
)
|
| 172 |
+
|
| 173 |
+
return prompt
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
def save_prompt_to_file(player_name, prompt, output_dir):
|
| 177 |
+
"""
|
| 178 |
+
Save a prompt as JSON file with response schema header.
|
| 179 |
+
|
| 180 |
+
Args:
|
| 181 |
+
player_name: Name of the player
|
| 182 |
+
prompt: Complete prompt dictionary
|
| 183 |
+
output_dir: Directory to save to
|
| 184 |
+
"""
|
| 185 |
+
output_file = output_dir / f"prompt_player_{player_name}.json"
|
| 186 |
+
|
| 187 |
+
# Create complete LLM request with schema + prompt
|
| 188 |
+
llm_request = {
|
| 189 |
+
"response_schema": get_response_schema(),
|
| 190 |
+
"system_instruction": "You are an expert Settlers of Catan player. Analyze the game state carefully and respond with your chosen action in the exact JSON format specified in response_schema.",
|
| 191 |
+
"prompt": prompt
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
with open(output_file, 'w', encoding='utf-8') as f:
|
| 195 |
+
json.dump(llm_request, f, indent=2, ensure_ascii=False)
|
| 196 |
+
|
| 197 |
+
# Also create a human-readable version
|
| 198 |
+
txt_file = output_dir / f"prompt_player_{player_name}.txt"
|
| 199 |
+
with open(txt_file, 'w', encoding='utf-8') as f:
|
| 200 |
+
f.write("="*80 + "\n")
|
| 201 |
+
f.write(f"AI AGENT PROMPT - PLAYER {player_name.upper()}\n")
|
| 202 |
+
f.write(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
|
| 203 |
+
f.write("="*80 + "\n\n")
|
| 204 |
+
|
| 205 |
+
f.write("📋 RESPONSE SCHEMA (Expected LLM Output Format)\n")
|
| 206 |
+
f.write("-" * 80 + "\n")
|
| 207 |
+
f.write(json.dumps(llm_request["response_schema"], indent=2, ensure_ascii=False))
|
| 208 |
+
f.write("\n\n")
|
| 209 |
+
|
| 210 |
+
f.write("="*80 + "\n")
|
| 211 |
+
f.write("📨 PROMPT TO SEND TO LLM\n")
|
| 212 |
+
f.write("="*80 + "\n\n")
|
| 213 |
+
|
| 214 |
+
f.write(json.dumps(prompt, indent=2, ensure_ascii=False))
|
| 215 |
+
f.write("\n\n")
|
| 216 |
+
|
| 217 |
+
f.write("="*80 + "\n")
|
| 218 |
+
f.write("END OF PROMPT\n")
|
| 219 |
+
f.write("="*80 + "\n")
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
def main():
|
| 223 |
+
"""Main entry point - generate prompts for all players."""
|
| 224 |
+
print("\n" + "="*80)
|
| 225 |
+
print("🎮 AI PROMPT GENERATOR - Real Game State")
|
| 226 |
+
print("="*80 + "\n")
|
| 227 |
+
|
| 228 |
+
# Load current game state
|
| 229 |
+
print("📖 Loading current game state...")
|
| 230 |
+
game_state = load_current_state()
|
| 231 |
+
|
| 232 |
+
if not game_state:
|
| 233 |
+
return
|
| 234 |
+
|
| 235 |
+
# Show basic info
|
| 236 |
+
meta = game_state.get("meta", {})
|
| 237 |
+
players = game_state.get("players", {})
|
| 238 |
+
|
| 239 |
+
print(f"✓ Loaded game state")
|
| 240 |
+
print(f" Phase: {meta.get('phase')}")
|
| 241 |
+
print(f" Current Player: {meta.get('curr')}")
|
| 242 |
+
print(f" Players: {', '.join(players.keys())}")
|
| 243 |
+
print()
|
| 244 |
+
|
| 245 |
+
# Create prompt manager
|
| 246 |
+
config = AIConfig()
|
| 247 |
+
prompt_manager = PromptManager(config)
|
| 248 |
+
|
| 249 |
+
# Create output directory
|
| 250 |
+
output_dir = Path('examples/ai_testing/my_games/prompts')
|
| 251 |
+
output_dir.mkdir(exist_ok=True, parents=True)
|
| 252 |
+
|
| 253 |
+
print("📝 Generating prompts for each player...\n")
|
| 254 |
+
|
| 255 |
+
# Generate prompt for each player
|
| 256 |
+
for player_name in players.keys():
|
| 257 |
+
print(f" ⚙️ Generating prompt for player '{player_name}'...")
|
| 258 |
+
|
| 259 |
+
try:
|
| 260 |
+
prompt = generate_prompt_for_player(player_name, game_state, prompt_manager)
|
| 261 |
+
save_prompt_to_file(player_name, prompt, output_dir)
|
| 262 |
+
|
| 263 |
+
json_file = output_dir / f"prompt_player_{player_name}.json"
|
| 264 |
+
txt_file = output_dir / f"prompt_player_{player_name}.txt"
|
| 265 |
+
print(f" ✓ JSON: {json_file}")
|
| 266 |
+
print(f" ✓ TXT: {txt_file}")
|
| 267 |
+
|
| 268 |
+
except Exception as e:
|
| 269 |
+
print(f" ❌ Error: {e}")
|
| 270 |
+
import traceback
|
| 271 |
+
traceback.print_exc()
|
| 272 |
+
|
| 273 |
+
print("\n" + "="*80)
|
| 274 |
+
print("✅ DONE! Prompts generated successfully")
|
| 275 |
+
print("="*80)
|
| 276 |
+
print(f"\n📁 Output location: {output_dir.absolute()}")
|
| 277 |
+
print(f"\n💡 Files created per player:")
|
| 278 |
+
print(f" - prompt_player_X.json (Send this to LLM)")
|
| 279 |
+
print(f" - prompt_player_X.txt (Human-readable)")
|
| 280 |
+
|
| 281 |
+
print("\n" + "="*80 + "\n")
|
| 282 |
+
|
| 283 |
+
|
| 284 |
+
if __name__ == '__main__':
|
| 285 |
+
main()
|
examples/ai_testing/my_games/current_state.json
ADDED
|
@@ -0,0 +1,891 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"timestamp": "2026-01-03T20:37:22.532273",
|
| 3 |
+
"state_number": 3,
|
| 4 |
+
"state": {
|
| 5 |
+
"hexes": [
|
| 6 |
+
{
|
| 7 |
+
"id": 1,
|
| 8 |
+
"type": "wood",
|
| 9 |
+
"number": 12,
|
| 10 |
+
"has_robber": false
|
| 11 |
+
},
|
| 12 |
+
{
|
| 13 |
+
"id": 2,
|
| 14 |
+
"type": "sheep",
|
| 15 |
+
"number": 5,
|
| 16 |
+
"has_robber": false
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"id": 3,
|
| 20 |
+
"type": "wood",
|
| 21 |
+
"number": 4,
|
| 22 |
+
"has_robber": false
|
| 23 |
+
},
|
| 24 |
+
{
|
| 25 |
+
"id": 4,
|
| 26 |
+
"type": "sheep",
|
| 27 |
+
"number": 8,
|
| 28 |
+
"has_robber": false
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"id": 5,
|
| 32 |
+
"type": "brick",
|
| 33 |
+
"number": 6,
|
| 34 |
+
"has_robber": false
|
| 35 |
+
},
|
| 36 |
+
{
|
| 37 |
+
"id": 6,
|
| 38 |
+
"type": "wood",
|
| 39 |
+
"number": 3,
|
| 40 |
+
"has_robber": false
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"id": 7,
|
| 44 |
+
"type": "wheat",
|
| 45 |
+
"number": 8,
|
| 46 |
+
"has_robber": false
|
| 47 |
+
},
|
| 48 |
+
{
|
| 49 |
+
"id": 8,
|
| 50 |
+
"type": "brick",
|
| 51 |
+
"number": 10,
|
| 52 |
+
"has_robber": false
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"id": 9,
|
| 56 |
+
"type": "wood",
|
| 57 |
+
"number": 11,
|
| 58 |
+
"has_robber": false
|
| 59 |
+
},
|
| 60 |
+
{
|
| 61 |
+
"id": 10,
|
| 62 |
+
"type": "desert",
|
| 63 |
+
"number": null,
|
| 64 |
+
"has_robber": true
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"id": 11,
|
| 68 |
+
"type": "ore",
|
| 69 |
+
"number": 3,
|
| 70 |
+
"has_robber": false
|
| 71 |
+
},
|
| 72 |
+
{
|
| 73 |
+
"id": 12,
|
| 74 |
+
"type": "sheep",
|
| 75 |
+
"number": 4,
|
| 76 |
+
"has_robber": false
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"id": 13,
|
| 80 |
+
"type": "brick",
|
| 81 |
+
"number": 10,
|
| 82 |
+
"has_robber": false
|
| 83 |
+
},
|
| 84 |
+
{
|
| 85 |
+
"id": 14,
|
| 86 |
+
"type": "wheat",
|
| 87 |
+
"number": 9,
|
| 88 |
+
"has_robber": false
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"id": 15,
|
| 92 |
+
"type": "wheat",
|
| 93 |
+
"number": 6,
|
| 94 |
+
"has_robber": false
|
| 95 |
+
},
|
| 96 |
+
{
|
| 97 |
+
"id": 16,
|
| 98 |
+
"type": "sheep",
|
| 99 |
+
"number": 11,
|
| 100 |
+
"has_robber": false
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"id": 17,
|
| 104 |
+
"type": "ore",
|
| 105 |
+
"number": 5,
|
| 106 |
+
"has_robber": false
|
| 107 |
+
},
|
| 108 |
+
{
|
| 109 |
+
"id": 18,
|
| 110 |
+
"type": "wheat",
|
| 111 |
+
"number": 9,
|
| 112 |
+
"has_robber": false
|
| 113 |
+
},
|
| 114 |
+
{
|
| 115 |
+
"id": 19,
|
| 116 |
+
"type": "ore",
|
| 117 |
+
"number": 2,
|
| 118 |
+
"has_robber": false
|
| 119 |
+
}
|
| 120 |
+
],
|
| 121 |
+
"settlements": [
|
| 122 |
+
{
|
| 123 |
+
"id": "b_20",
|
| 124 |
+
"vertex": 20,
|
| 125 |
+
"player": 1
|
| 126 |
+
}
|
| 127 |
+
],
|
| 128 |
+
"cities": [],
|
| 129 |
+
"roads": [],
|
| 130 |
+
"harbors": [
|
| 131 |
+
{
|
| 132 |
+
"id": 1,
|
| 133 |
+
"type": "any",
|
| 134 |
+
"ratio": 3,
|
| 135 |
+
"point_one": 9,
|
| 136 |
+
"point_two": 8
|
| 137 |
+
},
|
| 138 |
+
{
|
| 139 |
+
"id": 2,
|
| 140 |
+
"type": "sheep",
|
| 141 |
+
"ratio": 2,
|
| 142 |
+
"point_one": 17,
|
| 143 |
+
"point_two": 28
|
| 144 |
+
},
|
| 145 |
+
{
|
| 146 |
+
"id": 3,
|
| 147 |
+
"type": "wood",
|
| 148 |
+
"ratio": 2,
|
| 149 |
+
"point_one": 40,
|
| 150 |
+
"point_two": 48
|
| 151 |
+
},
|
| 152 |
+
{
|
| 153 |
+
"id": 4,
|
| 154 |
+
"type": "any",
|
| 155 |
+
"ratio": 3,
|
| 156 |
+
"point_one": 50,
|
| 157 |
+
"point_two": 51
|
| 158 |
+
},
|
| 159 |
+
{
|
| 160 |
+
"id": 5,
|
| 161 |
+
"type": "any",
|
| 162 |
+
"ratio": 3,
|
| 163 |
+
"point_one": 53,
|
| 164 |
+
"point_two": 54
|
| 165 |
+
},
|
| 166 |
+
{
|
| 167 |
+
"id": 6,
|
| 168 |
+
"type": "any",
|
| 169 |
+
"ratio": 3,
|
| 170 |
+
"point_one": 37,
|
| 171 |
+
"point_two": 38
|
| 172 |
+
},
|
| 173 |
+
{
|
| 174 |
+
"id": 7,
|
| 175 |
+
"type": "ore",
|
| 176 |
+
"ratio": 2,
|
| 177 |
+
"point_one": 26,
|
| 178 |
+
"point_two": 16
|
| 179 |
+
},
|
| 180 |
+
{
|
| 181 |
+
"id": 8,
|
| 182 |
+
"type": "brick",
|
| 183 |
+
"ratio": 2,
|
| 184 |
+
"point_one": 7,
|
| 185 |
+
"point_two": 6
|
| 186 |
+
},
|
| 187 |
+
{
|
| 188 |
+
"id": 9,
|
| 189 |
+
"type": "wheat",
|
| 190 |
+
"ratio": 2,
|
| 191 |
+
"point_one": 3,
|
| 192 |
+
"point_two": 2
|
| 193 |
+
}
|
| 194 |
+
],
|
| 195 |
+
"players": [
|
| 196 |
+
{
|
| 197 |
+
"id": 0,
|
| 198 |
+
"name": "a",
|
| 199 |
+
"victory_points": 1,
|
| 200 |
+
"total_cards": 0,
|
| 201 |
+
"cards_list": [],
|
| 202 |
+
"dev_cards_list": [],
|
| 203 |
+
"settlements": 1,
|
| 204 |
+
"cities": 0,
|
| 205 |
+
"roads": 0,
|
| 206 |
+
"longest_road": 0,
|
| 207 |
+
"has_longest_road": false,
|
| 208 |
+
"knights": 0,
|
| 209 |
+
"knights_played": 0,
|
| 210 |
+
"has_largest_army": false
|
| 211 |
+
},
|
| 212 |
+
{
|
| 213 |
+
"id": 1,
|
| 214 |
+
"name": "b",
|
| 215 |
+
"victory_points": 0,
|
| 216 |
+
"total_cards": 0,
|
| 217 |
+
"cards_list": [],
|
| 218 |
+
"dev_cards_list": [],
|
| 219 |
+
"settlements": 0,
|
| 220 |
+
"cities": 0,
|
| 221 |
+
"roads": 0,
|
| 222 |
+
"longest_road": 0,
|
| 223 |
+
"has_longest_road": false,
|
| 224 |
+
"knights": 0,
|
| 225 |
+
"knights_played": 0,
|
| 226 |
+
"has_largest_army": false
|
| 227 |
+
},
|
| 228 |
+
{
|
| 229 |
+
"id": 2,
|
| 230 |
+
"name": "c",
|
| 231 |
+
"victory_points": 0,
|
| 232 |
+
"total_cards": 0,
|
| 233 |
+
"cards_list": [],
|
| 234 |
+
"dev_cards_list": [],
|
| 235 |
+
"settlements": 0,
|
| 236 |
+
"cities": 0,
|
| 237 |
+
"roads": 0,
|
| 238 |
+
"longest_road": 0,
|
| 239 |
+
"has_longest_road": false,
|
| 240 |
+
"knights": 0,
|
| 241 |
+
"knights_played": 0,
|
| 242 |
+
"has_largest_army": false
|
| 243 |
+
}
|
| 244 |
+
],
|
| 245 |
+
"current_player": 0,
|
| 246 |
+
"current_phase": "SETUP_FIRST_ROUND",
|
| 247 |
+
"robber_position": [
|
| 248 |
+
2,
|
| 249 |
+
2
|
| 250 |
+
],
|
| 251 |
+
"dice_result": null,
|
| 252 |
+
"points": [
|
| 253 |
+
{
|
| 254 |
+
"point_id": 1,
|
| 255 |
+
"adjacent_points": [
|
| 256 |
+
2,
|
| 257 |
+
9
|
| 258 |
+
],
|
| 259 |
+
"adjacent_hexes": [
|
| 260 |
+
1
|
| 261 |
+
]
|
| 262 |
+
},
|
| 263 |
+
{
|
| 264 |
+
"point_id": 2,
|
| 265 |
+
"adjacent_points": [
|
| 266 |
+
1,
|
| 267 |
+
3
|
| 268 |
+
],
|
| 269 |
+
"adjacent_hexes": [
|
| 270 |
+
1
|
| 271 |
+
]
|
| 272 |
+
},
|
| 273 |
+
{
|
| 274 |
+
"point_id": 3,
|
| 275 |
+
"adjacent_points": [
|
| 276 |
+
2,
|
| 277 |
+
4,
|
| 278 |
+
11
|
| 279 |
+
],
|
| 280 |
+
"adjacent_hexes": [
|
| 281 |
+
2,
|
| 282 |
+
1
|
| 283 |
+
]
|
| 284 |
+
},
|
| 285 |
+
{
|
| 286 |
+
"point_id": 4,
|
| 287 |
+
"adjacent_points": [
|
| 288 |
+
3,
|
| 289 |
+
5
|
| 290 |
+
],
|
| 291 |
+
"adjacent_hexes": [
|
| 292 |
+
2
|
| 293 |
+
]
|
| 294 |
+
},
|
| 295 |
+
{
|
| 296 |
+
"point_id": 5,
|
| 297 |
+
"adjacent_points": [
|
| 298 |
+
4,
|
| 299 |
+
6,
|
| 300 |
+
13
|
| 301 |
+
],
|
| 302 |
+
"adjacent_hexes": [
|
| 303 |
+
3,
|
| 304 |
+
2
|
| 305 |
+
]
|
| 306 |
+
},
|
| 307 |
+
{
|
| 308 |
+
"point_id": 6,
|
| 309 |
+
"adjacent_points": [
|
| 310 |
+
5,
|
| 311 |
+
7
|
| 312 |
+
],
|
| 313 |
+
"adjacent_hexes": [
|
| 314 |
+
3
|
| 315 |
+
]
|
| 316 |
+
},
|
| 317 |
+
{
|
| 318 |
+
"point_id": 7,
|
| 319 |
+
"adjacent_points": [
|
| 320 |
+
6,
|
| 321 |
+
15
|
| 322 |
+
],
|
| 323 |
+
"adjacent_hexes": [
|
| 324 |
+
3
|
| 325 |
+
]
|
| 326 |
+
},
|
| 327 |
+
{
|
| 328 |
+
"point_id": 8,
|
| 329 |
+
"adjacent_points": [
|
| 330 |
+
9,
|
| 331 |
+
18
|
| 332 |
+
],
|
| 333 |
+
"adjacent_hexes": [
|
| 334 |
+
4
|
| 335 |
+
]
|
| 336 |
+
},
|
| 337 |
+
{
|
| 338 |
+
"point_id": 9,
|
| 339 |
+
"adjacent_points": [
|
| 340 |
+
8,
|
| 341 |
+
10,
|
| 342 |
+
1
|
| 343 |
+
],
|
| 344 |
+
"adjacent_hexes": [
|
| 345 |
+
4,
|
| 346 |
+
1
|
| 347 |
+
]
|
| 348 |
+
},
|
| 349 |
+
{
|
| 350 |
+
"point_id": 10,
|
| 351 |
+
"adjacent_points": [
|
| 352 |
+
9,
|
| 353 |
+
11,
|
| 354 |
+
20
|
| 355 |
+
],
|
| 356 |
+
"adjacent_hexes": [
|
| 357 |
+
5,
|
| 358 |
+
4,
|
| 359 |
+
1
|
| 360 |
+
]
|
| 361 |
+
},
|
| 362 |
+
{
|
| 363 |
+
"point_id": 11,
|
| 364 |
+
"adjacent_points": [
|
| 365 |
+
10,
|
| 366 |
+
12,
|
| 367 |
+
3
|
| 368 |
+
],
|
| 369 |
+
"adjacent_hexes": [
|
| 370 |
+
5,
|
| 371 |
+
2,
|
| 372 |
+
1
|
| 373 |
+
]
|
| 374 |
+
},
|
| 375 |
+
{
|
| 376 |
+
"point_id": 12,
|
| 377 |
+
"adjacent_points": [
|
| 378 |
+
11,
|
| 379 |
+
13,
|
| 380 |
+
22
|
| 381 |
+
],
|
| 382 |
+
"adjacent_hexes": [
|
| 383 |
+
6,
|
| 384 |
+
5,
|
| 385 |
+
2
|
| 386 |
+
]
|
| 387 |
+
},
|
| 388 |
+
{
|
| 389 |
+
"point_id": 13,
|
| 390 |
+
"adjacent_points": [
|
| 391 |
+
12,
|
| 392 |
+
14,
|
| 393 |
+
5
|
| 394 |
+
],
|
| 395 |
+
"adjacent_hexes": [
|
| 396 |
+
6,
|
| 397 |
+
3,
|
| 398 |
+
2
|
| 399 |
+
]
|
| 400 |
+
},
|
| 401 |
+
{
|
| 402 |
+
"point_id": 14,
|
| 403 |
+
"adjacent_points": [
|
| 404 |
+
13,
|
| 405 |
+
15,
|
| 406 |
+
24
|
| 407 |
+
],
|
| 408 |
+
"adjacent_hexes": [
|
| 409 |
+
7,
|
| 410 |
+
6,
|
| 411 |
+
3
|
| 412 |
+
]
|
| 413 |
+
},
|
| 414 |
+
{
|
| 415 |
+
"point_id": 15,
|
| 416 |
+
"adjacent_points": [
|
| 417 |
+
14,
|
| 418 |
+
16,
|
| 419 |
+
7
|
| 420 |
+
],
|
| 421 |
+
"adjacent_hexes": [
|
| 422 |
+
7,
|
| 423 |
+
3
|
| 424 |
+
]
|
| 425 |
+
},
|
| 426 |
+
{
|
| 427 |
+
"point_id": 16,
|
| 428 |
+
"adjacent_points": [
|
| 429 |
+
15,
|
| 430 |
+
26
|
| 431 |
+
],
|
| 432 |
+
"adjacent_hexes": [
|
| 433 |
+
7
|
| 434 |
+
]
|
| 435 |
+
},
|
| 436 |
+
{
|
| 437 |
+
"point_id": 17,
|
| 438 |
+
"adjacent_points": [
|
| 439 |
+
18,
|
| 440 |
+
28
|
| 441 |
+
],
|
| 442 |
+
"adjacent_hexes": [
|
| 443 |
+
8
|
| 444 |
+
]
|
| 445 |
+
},
|
| 446 |
+
{
|
| 447 |
+
"point_id": 18,
|
| 448 |
+
"adjacent_points": [
|
| 449 |
+
17,
|
| 450 |
+
19,
|
| 451 |
+
8
|
| 452 |
+
],
|
| 453 |
+
"adjacent_hexes": [
|
| 454 |
+
8,
|
| 455 |
+
4
|
| 456 |
+
]
|
| 457 |
+
},
|
| 458 |
+
{
|
| 459 |
+
"point_id": 19,
|
| 460 |
+
"adjacent_points": [
|
| 461 |
+
18,
|
| 462 |
+
20,
|
| 463 |
+
30
|
| 464 |
+
],
|
| 465 |
+
"adjacent_hexes": [
|
| 466 |
+
9,
|
| 467 |
+
8,
|
| 468 |
+
4
|
| 469 |
+
]
|
| 470 |
+
},
|
| 471 |
+
{
|
| 472 |
+
"point_id": 20,
|
| 473 |
+
"adjacent_points": [
|
| 474 |
+
19,
|
| 475 |
+
21,
|
| 476 |
+
10
|
| 477 |
+
],
|
| 478 |
+
"adjacent_hexes": [
|
| 479 |
+
9,
|
| 480 |
+
5,
|
| 481 |
+
4
|
| 482 |
+
]
|
| 483 |
+
},
|
| 484 |
+
{
|
| 485 |
+
"point_id": 21,
|
| 486 |
+
"adjacent_points": [
|
| 487 |
+
20,
|
| 488 |
+
22,
|
| 489 |
+
32
|
| 490 |
+
],
|
| 491 |
+
"adjacent_hexes": [
|
| 492 |
+
10,
|
| 493 |
+
9,
|
| 494 |
+
5
|
| 495 |
+
]
|
| 496 |
+
},
|
| 497 |
+
{
|
| 498 |
+
"point_id": 22,
|
| 499 |
+
"adjacent_points": [
|
| 500 |
+
21,
|
| 501 |
+
23,
|
| 502 |
+
12
|
| 503 |
+
],
|
| 504 |
+
"adjacent_hexes": [
|
| 505 |
+
10,
|
| 506 |
+
6,
|
| 507 |
+
5
|
| 508 |
+
]
|
| 509 |
+
},
|
| 510 |
+
{
|
| 511 |
+
"point_id": 23,
|
| 512 |
+
"adjacent_points": [
|
| 513 |
+
22,
|
| 514 |
+
24,
|
| 515 |
+
34
|
| 516 |
+
],
|
| 517 |
+
"adjacent_hexes": [
|
| 518 |
+
11,
|
| 519 |
+
10,
|
| 520 |
+
6
|
| 521 |
+
]
|
| 522 |
+
},
|
| 523 |
+
{
|
| 524 |
+
"point_id": 24,
|
| 525 |
+
"adjacent_points": [
|
| 526 |
+
23,
|
| 527 |
+
25,
|
| 528 |
+
14
|
| 529 |
+
],
|
| 530 |
+
"adjacent_hexes": [
|
| 531 |
+
11,
|
| 532 |
+
7,
|
| 533 |
+
6
|
| 534 |
+
]
|
| 535 |
+
},
|
| 536 |
+
{
|
| 537 |
+
"point_id": 25,
|
| 538 |
+
"adjacent_points": [
|
| 539 |
+
24,
|
| 540 |
+
26,
|
| 541 |
+
36
|
| 542 |
+
],
|
| 543 |
+
"adjacent_hexes": [
|
| 544 |
+
12,
|
| 545 |
+
11,
|
| 546 |
+
7
|
| 547 |
+
]
|
| 548 |
+
},
|
| 549 |
+
{
|
| 550 |
+
"point_id": 26,
|
| 551 |
+
"adjacent_points": [
|
| 552 |
+
25,
|
| 553 |
+
27,
|
| 554 |
+
16
|
| 555 |
+
],
|
| 556 |
+
"adjacent_hexes": [
|
| 557 |
+
12,
|
| 558 |
+
7
|
| 559 |
+
]
|
| 560 |
+
},
|
| 561 |
+
{
|
| 562 |
+
"point_id": 27,
|
| 563 |
+
"adjacent_points": [
|
| 564 |
+
26,
|
| 565 |
+
38
|
| 566 |
+
],
|
| 567 |
+
"adjacent_hexes": [
|
| 568 |
+
12
|
| 569 |
+
]
|
| 570 |
+
},
|
| 571 |
+
{
|
| 572 |
+
"point_id": 28,
|
| 573 |
+
"adjacent_points": [
|
| 574 |
+
29,
|
| 575 |
+
17
|
| 576 |
+
],
|
| 577 |
+
"adjacent_hexes": [
|
| 578 |
+
8
|
| 579 |
+
]
|
| 580 |
+
},
|
| 581 |
+
{
|
| 582 |
+
"point_id": 29,
|
| 583 |
+
"adjacent_points": [
|
| 584 |
+
28,
|
| 585 |
+
30,
|
| 586 |
+
39
|
| 587 |
+
],
|
| 588 |
+
"adjacent_hexes": [
|
| 589 |
+
13,
|
| 590 |
+
8
|
| 591 |
+
]
|
| 592 |
+
},
|
| 593 |
+
{
|
| 594 |
+
"point_id": 30,
|
| 595 |
+
"adjacent_points": [
|
| 596 |
+
29,
|
| 597 |
+
31,
|
| 598 |
+
19
|
| 599 |
+
],
|
| 600 |
+
"adjacent_hexes": [
|
| 601 |
+
13,
|
| 602 |
+
9,
|
| 603 |
+
8
|
| 604 |
+
]
|
| 605 |
+
},
|
| 606 |
+
{
|
| 607 |
+
"point_id": 31,
|
| 608 |
+
"adjacent_points": [
|
| 609 |
+
30,
|
| 610 |
+
32,
|
| 611 |
+
41
|
| 612 |
+
],
|
| 613 |
+
"adjacent_hexes": [
|
| 614 |
+
14,
|
| 615 |
+
13,
|
| 616 |
+
9
|
| 617 |
+
]
|
| 618 |
+
},
|
| 619 |
+
{
|
| 620 |
+
"point_id": 32,
|
| 621 |
+
"adjacent_points": [
|
| 622 |
+
31,
|
| 623 |
+
33,
|
| 624 |
+
21
|
| 625 |
+
],
|
| 626 |
+
"adjacent_hexes": [
|
| 627 |
+
14,
|
| 628 |
+
10,
|
| 629 |
+
9
|
| 630 |
+
]
|
| 631 |
+
},
|
| 632 |
+
{
|
| 633 |
+
"point_id": 33,
|
| 634 |
+
"adjacent_points": [
|
| 635 |
+
32,
|
| 636 |
+
34,
|
| 637 |
+
43
|
| 638 |
+
],
|
| 639 |
+
"adjacent_hexes": [
|
| 640 |
+
15,
|
| 641 |
+
14,
|
| 642 |
+
10
|
| 643 |
+
]
|
| 644 |
+
},
|
| 645 |
+
{
|
| 646 |
+
"point_id": 34,
|
| 647 |
+
"adjacent_points": [
|
| 648 |
+
33,
|
| 649 |
+
35,
|
| 650 |
+
23
|
| 651 |
+
],
|
| 652 |
+
"adjacent_hexes": [
|
| 653 |
+
15,
|
| 654 |
+
11,
|
| 655 |
+
10
|
| 656 |
+
]
|
| 657 |
+
},
|
| 658 |
+
{
|
| 659 |
+
"point_id": 35,
|
| 660 |
+
"adjacent_points": [
|
| 661 |
+
34,
|
| 662 |
+
36,
|
| 663 |
+
45
|
| 664 |
+
],
|
| 665 |
+
"adjacent_hexes": [
|
| 666 |
+
16,
|
| 667 |
+
15,
|
| 668 |
+
11
|
| 669 |
+
]
|
| 670 |
+
},
|
| 671 |
+
{
|
| 672 |
+
"point_id": 36,
|
| 673 |
+
"adjacent_points": [
|
| 674 |
+
35,
|
| 675 |
+
37,
|
| 676 |
+
25
|
| 677 |
+
],
|
| 678 |
+
"adjacent_hexes": [
|
| 679 |
+
16,
|
| 680 |
+
12,
|
| 681 |
+
11
|
| 682 |
+
]
|
| 683 |
+
},
|
| 684 |
+
{
|
| 685 |
+
"point_id": 37,
|
| 686 |
+
"adjacent_points": [
|
| 687 |
+
36,
|
| 688 |
+
38,
|
| 689 |
+
47
|
| 690 |
+
],
|
| 691 |
+
"adjacent_hexes": [
|
| 692 |
+
16,
|
| 693 |
+
12
|
| 694 |
+
]
|
| 695 |
+
},
|
| 696 |
+
{
|
| 697 |
+
"point_id": 38,
|
| 698 |
+
"adjacent_points": [
|
| 699 |
+
37,
|
| 700 |
+
27
|
| 701 |
+
],
|
| 702 |
+
"adjacent_hexes": [
|
| 703 |
+
12
|
| 704 |
+
]
|
| 705 |
+
},
|
| 706 |
+
{
|
| 707 |
+
"point_id": 39,
|
| 708 |
+
"adjacent_points": [
|
| 709 |
+
40,
|
| 710 |
+
29
|
| 711 |
+
],
|
| 712 |
+
"adjacent_hexes": [
|
| 713 |
+
13
|
| 714 |
+
]
|
| 715 |
+
},
|
| 716 |
+
{
|
| 717 |
+
"point_id": 40,
|
| 718 |
+
"adjacent_points": [
|
| 719 |
+
39,
|
| 720 |
+
41,
|
| 721 |
+
48
|
| 722 |
+
],
|
| 723 |
+
"adjacent_hexes": [
|
| 724 |
+
17,
|
| 725 |
+
13
|
| 726 |
+
]
|
| 727 |
+
},
|
| 728 |
+
{
|
| 729 |
+
"point_id": 41,
|
| 730 |
+
"adjacent_points": [
|
| 731 |
+
40,
|
| 732 |
+
42,
|
| 733 |
+
31
|
| 734 |
+
],
|
| 735 |
+
"adjacent_hexes": [
|
| 736 |
+
17,
|
| 737 |
+
14,
|
| 738 |
+
13
|
| 739 |
+
]
|
| 740 |
+
},
|
| 741 |
+
{
|
| 742 |
+
"point_id": 42,
|
| 743 |
+
"adjacent_points": [
|
| 744 |
+
41,
|
| 745 |
+
43,
|
| 746 |
+
50
|
| 747 |
+
],
|
| 748 |
+
"adjacent_hexes": [
|
| 749 |
+
18,
|
| 750 |
+
17,
|
| 751 |
+
14
|
| 752 |
+
]
|
| 753 |
+
},
|
| 754 |
+
{
|
| 755 |
+
"point_id": 43,
|
| 756 |
+
"adjacent_points": [
|
| 757 |
+
42,
|
| 758 |
+
44,
|
| 759 |
+
33
|
| 760 |
+
],
|
| 761 |
+
"adjacent_hexes": [
|
| 762 |
+
18,
|
| 763 |
+
15,
|
| 764 |
+
14
|
| 765 |
+
]
|
| 766 |
+
},
|
| 767 |
+
{
|
| 768 |
+
"point_id": 44,
|
| 769 |
+
"adjacent_points": [
|
| 770 |
+
43,
|
| 771 |
+
45,
|
| 772 |
+
52
|
| 773 |
+
],
|
| 774 |
+
"adjacent_hexes": [
|
| 775 |
+
19,
|
| 776 |
+
18,
|
| 777 |
+
15
|
| 778 |
+
]
|
| 779 |
+
},
|
| 780 |
+
{
|
| 781 |
+
"point_id": 45,
|
| 782 |
+
"adjacent_points": [
|
| 783 |
+
44,
|
| 784 |
+
46,
|
| 785 |
+
35
|
| 786 |
+
],
|
| 787 |
+
"adjacent_hexes": [
|
| 788 |
+
19,
|
| 789 |
+
16,
|
| 790 |
+
15
|
| 791 |
+
]
|
| 792 |
+
},
|
| 793 |
+
{
|
| 794 |
+
"point_id": 46,
|
| 795 |
+
"adjacent_points": [
|
| 796 |
+
45,
|
| 797 |
+
47,
|
| 798 |
+
54
|
| 799 |
+
],
|
| 800 |
+
"adjacent_hexes": [
|
| 801 |
+
19,
|
| 802 |
+
16
|
| 803 |
+
]
|
| 804 |
+
},
|
| 805 |
+
{
|
| 806 |
+
"point_id": 47,
|
| 807 |
+
"adjacent_points": [
|
| 808 |
+
46,
|
| 809 |
+
37
|
| 810 |
+
],
|
| 811 |
+
"adjacent_hexes": [
|
| 812 |
+
16
|
| 813 |
+
]
|
| 814 |
+
},
|
| 815 |
+
{
|
| 816 |
+
"point_id": 48,
|
| 817 |
+
"adjacent_points": [
|
| 818 |
+
49,
|
| 819 |
+
40
|
| 820 |
+
],
|
| 821 |
+
"adjacent_hexes": [
|
| 822 |
+
17
|
| 823 |
+
]
|
| 824 |
+
},
|
| 825 |
+
{
|
| 826 |
+
"point_id": 49,
|
| 827 |
+
"adjacent_points": [
|
| 828 |
+
48,
|
| 829 |
+
50
|
| 830 |
+
],
|
| 831 |
+
"adjacent_hexes": [
|
| 832 |
+
17
|
| 833 |
+
]
|
| 834 |
+
},
|
| 835 |
+
{
|
| 836 |
+
"point_id": 50,
|
| 837 |
+
"adjacent_points": [
|
| 838 |
+
49,
|
| 839 |
+
51,
|
| 840 |
+
42
|
| 841 |
+
],
|
| 842 |
+
"adjacent_hexes": [
|
| 843 |
+
18,
|
| 844 |
+
17
|
| 845 |
+
]
|
| 846 |
+
},
|
| 847 |
+
{
|
| 848 |
+
"point_id": 51,
|
| 849 |
+
"adjacent_points": [
|
| 850 |
+
50,
|
| 851 |
+
52
|
| 852 |
+
],
|
| 853 |
+
"adjacent_hexes": [
|
| 854 |
+
18
|
| 855 |
+
]
|
| 856 |
+
},
|
| 857 |
+
{
|
| 858 |
+
"point_id": 52,
|
| 859 |
+
"adjacent_points": [
|
| 860 |
+
51,
|
| 861 |
+
53,
|
| 862 |
+
44
|
| 863 |
+
],
|
| 864 |
+
"adjacent_hexes": [
|
| 865 |
+
19,
|
| 866 |
+
18
|
| 867 |
+
]
|
| 868 |
+
},
|
| 869 |
+
{
|
| 870 |
+
"point_id": 53,
|
| 871 |
+
"adjacent_points": [
|
| 872 |
+
52,
|
| 873 |
+
54
|
| 874 |
+
],
|
| 875 |
+
"adjacent_hexes": [
|
| 876 |
+
19
|
| 877 |
+
]
|
| 878 |
+
},
|
| 879 |
+
{
|
| 880 |
+
"point_id": 54,
|
| 881 |
+
"adjacent_points": [
|
| 882 |
+
53,
|
| 883 |
+
46
|
| 884 |
+
],
|
| 885 |
+
"adjacent_hexes": [
|
| 886 |
+
19
|
| 887 |
+
]
|
| 888 |
+
}
|
| 889 |
+
]
|
| 890 |
+
}
|
| 891 |
+
}
|
examples/ai_testing/my_games/current_state_optimized.txt
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
1. LOOKUP TABLES:
|
| 2 |
+
• "H" (Hexes): Array where Index = HexID. Value = Resource+Num.
|
| 3 |
+
Example: H[1]="W12" -> Hex 1 is Wood 12.
|
| 4 |
+
• "N" (Nodes): Array where Index = NodeID.
|
| 5 |
+
Format: [ [Neighbors], [HexIDs], Port? ]
|
| 6 |
+
Logic: To find yield of Node 10, check N[10]. Get HexIDs (e.g. [1,5]). Look up H[1] and H[5].
|
| 7 |
+
|
| 8 |
+
2. CODES: W=Wood, B=Brick, S=Sheep, Wh=Wheat, O=Ore, D=Desert.
|
| 9 |
+
?3=Any 3:1 port, X2=Specific Resource 2:1 port.
|
| 10 |
+
|
| 11 |
+
3. STATE: "bld"=[NodeID, Owner, Type], "rds"=[[From,To], Owner].
|
| 12 |
+
|
| 13 |
+
4. PLAYERS: "res"={Resource:Count}, "dev"={"h":[Hidden Cards], "r":[Revealed] (K=Knight)},
|
| 14 |
+
"stat"=["LR" (Longest Road), "LA" (Largest Army)].
|
| 15 |
+
|
| 16 |
+
5. ROBBER: Located at HexID specified in "meta.robber". H[id] is blocked.
|
| 17 |
+
|
| 18 |
+
JSON:
|
| 19 |
+
{
|
| 20 |
+
"meta":{"curr":"a","phase":"SETUP_FIRST_ROUND","robber":10,"dice":null},
|
| 21 |
+
"H":["","W12","S5","W4","S8","B6","W3","Wh8","B10","W11","D","O3","S4","B10","Wh9","Wh6","S11","O5","Wh9","O2"],
|
| 22 |
+
"N":[null,[[2,9],[1]],[[1,3],[1],"Wh2"],[[2,4,11],[2,1],"Wh2"],[[3,5],[2]],[[4,6,13],[3,2]],[[5,7],[3],"B2"],[[6,15],[3],"B2"],[[9,18],[4],"?3"],[[8,10,1],[4,1],"?3"],[[9,11,20],[5,4,1]],[[10,12,3],[5,2,1]],[[11,13,22],[6,5,2]],[[12,14,5],[6,3,2]],[[13,15,24],[7,6,3]],[[14,16,7],[7,3]],[[15,26],[7],"O2"],[[18,28],[8],"S2"],[[17,19,8],[8,4]],[[18,20,30],[9,8,4]],[[19,21,10],[9,5,4]],[[20,22,32],[10,9,5]],[[21,23,12],[10,6,5]],[[22,24,34],[11,10,6]],[[23,25,14],[11,7,6]],[[24,26,36],[12,11,7]],[[25,27,16],[12,7],"O2"],[[26,38],[12]],[[29,17],[8],"S2"],[[28,30,39],[13,8]],[[29,31,19],[13,9,8]],[[30,32,41],[14,13,9]],[[31,33,21],[14,10,9]],[[32,34,43],[15,14,10]],[[33,35,23],[15,11,10]],[[34,36,45],[16,15,11]],[[35,37,25],[16,12,11]],[[36,38,47],[16,12],"?3"],[[37,27],[12],"?3"],[[40,29],[13]],[[39,41,48],[17,13],"W2"],[[40,42,31],[17,14,13]],[[41,43,50],[18,17,14]],[[42,44,33],[18,15,14]],[[43,45,52],[19,18,15]],[[44,46,35],[19,16,15]],[[45,47,54],[19,16]],[[46,37],[16]],[[49,40],[17],"W2"],[[48,50],[17]],[[49,51,42],[18,17],"?3"],[[50,52],[18],"?3"],[[51,53,44],[19,18]],[[52,54],[19],"?3"],[[53,46],[19],"?3"]],
|
| 23 |
+
"state":{"bld":[[20,"a","S"]],"rds":[]},
|
| 24 |
+
"players":{"a":{"vp":1,"res":{}},"b":{"vp":0,"res":{}},"c":{"vp":0,"res":{}}}
|
| 25 |
+
}
|
examples/ai_testing/my_games/prompts/a
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
================================================================================
|
| 2 |
+
AI AGENT PROMPT - PLAYER A
|
| 3 |
+
Generated: 2026-01-03 20:17:07
|
| 4 |
+
================================================================================
|
| 5 |
+
|
| 6 |
+
📋 RESPONSE SCHEMA (Expected LLM Output Format)
|
| 7 |
+
--------------------------------------------------------------------------------
|
| 8 |
+
{
|
| 9 |
+
"type": "object",
|
| 10 |
+
"required": [
|
| 11 |
+
"internal_thinking",
|
| 12 |
+
"action"
|
| 13 |
+
],
|
| 14 |
+
"properties": {
|
| 15 |
+
"internal_thinking": {
|
| 16 |
+
"type": "string",
|
| 17 |
+
"description": "Your private reasoning about the situation, strategy, and decision-making process. This is for you only.",
|
| 18 |
+
"minLength": 50
|
| 19 |
+
},
|
| 20 |
+
"note_to_self": {
|
| 21 |
+
"type": "string",
|
| 22 |
+
"description": "A note to remember for next turn. What are you waiting for? What's your plan?",
|
| 23 |
+
"examples": [
|
| 24 |
+
"Waiting for Red's response on trade",
|
| 25 |
+
"Focus on building toward ore port next",
|
| 26 |
+
"Watch Blue's progress on longest road"
|
| 27 |
+
]
|
| 28 |
+
},
|
| 29 |
+
"say_outloud": {
|
| 30 |
+
"type": "string",
|
| 31 |
+
"description": "What you want to say to other players (chat message). Use this for negotiation, threats, or table talk.",
|
| 32 |
+
"examples": [
|
| 33 |
+
"Anyone want to trade sheep for wood?",
|
| 34 |
+
"Red, can you give me 1 Brick for 2 Sheep?",
|
| 35 |
+
"I'm so behind, don't steal from me!"
|
| 36 |
+
]
|
| 37 |
+
},
|
| 38 |
+
"action": {
|
| 39 |
+
"type": "object",
|
| 40 |
+
"required": [
|
| 41 |
+
"type",
|
| 42 |
+
"parameters"
|
| 43 |
+
],
|
| 44 |
+
"properties": {
|
| 45 |
+
"type": {
|
| 46 |
+
"type": "string",
|
| 47 |
+
"description": "The action type (must match one from allowed_actions in constraints)",
|
| 48 |
+
"examples": [
|
| 49 |
+
"BUILD_SETTLEMENT",
|
| 50 |
+
"BUILD_ROAD",
|
| 51 |
+
"OFFER_TRADE",
|
| 52 |
+
"WAIT_FOR_RESPONSE",
|
| 53 |
+
"END_TURN"
|
| 54 |
+
]
|
| 55 |
+
},
|
| 56 |
+
"parameters": {
|
| 57 |
+
"type": "object",
|
| 58 |
+
"description": "Action-specific parameters (structure matches allowed_actions examples)"
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
}
|
| 62 |
+
},
|
| 63 |
+
"example": {
|
| 64 |
+
"internal_thinking": "I have 3 Sheep and 2 Wheat. I need Wood and Brick to build. I see Red asked for Sheep in the chat. My note says to trade with Red. I will offer him a deal verbally first to see if he accepts, before committing to a formal trade action. I won't pass turn yet.",
|
| 65 |
+
"note_to_self": "Waiting for Red's response. If he says yes, I will use OFFER_TRADE action next.",
|
| 66 |
+
"say_outloud": "Red, I have plenty of sheep. Can you give me 1 Wood and 1 Brick for 2 Sheep?",
|
| 67 |
+
"action": {
|
| 68 |
+
"type": "WAIT_FOR_RESPONSE",
|
| 69 |
+
"parameters": {}
|
| 70 |
+
}
|
| 71 |
+
}
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
================================================================================
|
| 75 |
+
📨 PROMPT TO SEND TO LLM
|
| 76 |
+
================================================================================
|
| 77 |
+
|
| 78 |
+
{
|
| 79 |
+
"meta_data": {
|
| 80 |
+
"agent_name": "a",
|
| 81 |
+
"my_color": "Red",
|
| 82 |
+
"role": "You are player 'a' (Red). Play strategically to win."
|
| 83 |
+
},
|
| 84 |
+
"task_context": {
|
| 85 |
+
"what_just_happened": "It's your turn in the setup phase. Place your first settlement.",
|
| 86 |
+
"instructions": "Analyze the game state and select the optimal move from 'allowed_actions'. Only one action is currently available."
|
| 87 |
+
},
|
| 88 |
+
"game_state": "\nFORMAT GUIDE:\n• H array: Index=HexID, Value=Resource+Number (W=Wood, B=Brick, S=Sheep, Wh=Wheat, O=Ore, D=Desert)\n• N array: Index=NodeID, Value=[[Neighbors], [HexIDs], Port?] where Port: ?3=Any(3:1), X2=Specific(2:1)\n• bld: [NodeID, Owner, Type] where Type: S=Settlement, C=City\n• rds: [[From, To], Owner]\n• Players res: {ResourceCode: Count}\n• Players dev: {\"h\": [Hidden], \"r\": [Revealed]} - Cards: K=Knight, M=Monopoly, Y=Year of Plenty, R=Road Building, V=Victory Point\n• Players stat: [\"LR\"=Longest Road, \"LA\"=Largest Army]\n\nGAME STATE:\n{\n \"meta\": {\n \"curr\": \"a\",\n \"phase\": \"SETUP_FIRST_ROUND\",\n \"robber\": 10,\n \"dice\": null\n },\n \"H\": [\n \"\",\n \"W12\",\n \"S5\",\n \"W4\",\n \"S8\",\n \"B6\",\n \"W3\",\n \"Wh8\",\n \"B10\",\n \"W11\",\n \"D\",\n \"O3\",\n \"S4\",\n \"B10\",\n \"Wh9\",\n \"Wh6\",\n \"S11\",\n \"O5\",\n \"Wh9\",\n \"O2\"\n ],\n \"N\": [\n null,\n [\n [\n 2,\n 9\n ],\n [\n 1\n ]\n ],\n [\n [\n 1,\n 3\n ],\n [\n 1\n ],\n \"Wh2\"\n ],\n [\n [\n 2,\n 4,\n 11\n ],\n [\n 2,\n 1\n ],\n \"Wh2\"\n ],\n [\n [\n 3,\n 5\n ],\n [\n 2\n ]\n ],\n [\n [\n 4,\n 6,\n 13\n ],\n [\n 3,\n 2\n ]\n ],\n [\n [\n 5,\n 7\n ],\n [\n 3\n ],\n \"B2\"\n ],\n [\n [\n 6,\n 15\n ],\n [\n 3\n ],\n \"B2\"\n ],\n [\n [\n 9,\n 18\n ],\n [\n 4\n ],\n \"?3\"\n ],\n [\n [\n 8,\n 10,\n 1\n ],\n [\n 4,\n 1\n ],\n \"?3\"\n ],\n [\n [\n 9,\n 11,\n 20\n ],\n [\n 5,\n 4,\n 1\n ]\n ],\n [\n [\n 10,\n 12,\n 3\n ],\n [\n 5,\n 2,\n 1\n ]\n ],\n [\n [\n 11,\n 13,\n 22\n ],\n [\n 6,\n 5,\n 2\n ]\n ],\n [\n [\n 12,\n 14,\n 5\n ],\n [\n 6,\n 3,\n 2\n ]\n ],\n [\n [\n 13,\n 15,\n 24\n ],\n [\n 7,\n 6,\n 3\n ]\n ],\n [\n [\n 14,\n 16,\n 7\n ],\n [\n 7,\n 3\n ]\n ],\n [\n [\n 15,\n 26\n ],\n [\n 7\n ],\n \"O2\"\n ],\n [\n [\n 18,\n 28\n ],\n [\n 8\n ],\n \"S2\"\n ],\n [\n [\n 17,\n 19,\n 8\n ],\n [\n 8,\n 4\n ]\n ],\n [\n [\n 18,\n 20,\n 30\n ],\n [\n 9,\n 8,\n 4\n ]\n ],\n [\n [\n 19,\n 21,\n 10\n ],\n [\n 9,\n 5,\n 4\n ]\n ],\n [\n [\n 20,\n 22,\n 32\n ],\n [\n 10,\n 9,\n 5\n ]\n ],\n [\n [\n 21,\n 23,\n 12\n ],\n [\n 10,\n 6,\n 5\n ]\n ],\n [\n [\n 22,\n 24,\n 34\n ],\n [\n 11,\n 10,\n 6\n ]\n ],\n [\n [\n 23,\n 25,\n 14\n ],\n [\n 11,\n 7,\n 6\n ]\n ],\n [\n [\n 24,\n 26,\n 36\n ],\n [\n 12,\n 11,\n 7\n ]\n ],\n [\n [\n 25,\n 27,\n 16\n ],\n [\n 12,\n 7\n ],\n \"O2\"\n ],\n [\n [\n 26,\n 38\n ],\n [\n 12\n ]\n ],\n [\n [\n 29,\n 17\n ],\n [\n 8\n ],\n \"S2\"\n ],\n [\n [\n 28,\n 30,\n 39\n ],\n [\n 13,\n 8\n ]\n ],\n [\n [\n 29,\n 31,\n 19\n ],\n [\n 13,\n 9,\n 8\n ]\n ],\n [\n [\n 30,\n 32,\n 41\n ],\n [\n 14,\n 13,\n 9\n ]\n ],\n [\n [\n 31,\n 33,\n 21\n ],\n [\n 14,\n 10,\n 9\n ]\n ],\n [\n [\n 32,\n 34,\n 43\n ],\n [\n 15,\n 14,\n 10\n ]\n ],\n [\n [\n 33,\n 35,\n 23\n ],\n [\n 15,\n 11,\n 10\n ]\n ],\n [\n [\n 34,\n 36,\n 45\n ],\n [\n 16,\n 15,\n 11\n ]\n ],\n [\n [\n 35,\n 37,\n 25\n ],\n [\n 16,\n 12,\n 11\n ]\n ],\n [\n [\n 36,\n 38,\n 47\n ],\n [\n 16,\n 12\n ],\n \"?3\"\n ],\n [\n [\n 37,\n 27\n ],\n [\n 12\n ],\n \"?3\"\n ],\n [\n [\n 40,\n 29\n ],\n [\n 13\n ]\n ],\n [\n [\n 39,\n 41,\n 48\n ],\n [\n 17,\n 13\n ],\n \"W2\"\n ],\n [\n [\n 40,\n 42,\n 31\n ],\n [\n 17,\n 14,\n 13\n ]\n ],\n [\n [\n 41,\n 43,\n 50\n ],\n [\n 18,\n 17,\n 14\n ]\n ],\n [\n [\n 42,\n 44,\n 33\n ],\n [\n 18,\n 15,\n 14\n ]\n ],\n [\n [\n 43,\n 45,\n 52\n ],\n [\n 19,\n 18,\n 15\n ]\n ],\n [\n [\n 44,\n 46,\n 35\n ],\n [\n 19,\n 16,\n 15\n ]\n ],\n [\n [\n 45,\n 47,\n 54\n ],\n [\n 19,\n 16\n ]\n ],\n [\n [\n 46,\n 37\n ],\n [\n 16\n ]\n ],\n [\n [\n 49,\n 40\n ],\n [\n 17\n ],\n \"W2\"\n ],\n [\n [\n 48,\n 50\n ],\n [\n 17\n ]\n ],\n [\n [\n 49,\n 51,\n 42\n ],\n [\n 18,\n 17\n ],\n \"?3\"\n ],\n [\n [\n 50,\n 52\n ],\n [\n 18\n ],\n \"?3\"\n ],\n [\n [\n 51,\n 53,\n 44\n ],\n [\n 19,\n 18\n ]\n ],\n [\n [\n 52,\n 54\n ],\n [\n 19\n ],\n \"?3\"\n ],\n [\n [\n 53,\n 46\n ],\n [\n 19\n ],\n \"?3\"\n ]\n ],\n \"state\": {\n \"bld\": [],\n \"rds\": []\n },\n \"players\": {\n \"a\": {\n \"vp\": 0,\n \"res\": {}\n },\n \"b\": {\n \"vp\": 0,\n \"res\": {}\n },\n \"c\": {\n \"vp\": 0,\n \"res\": {}\n }\n }\n}",
|
| 89 |
+
"constraints": {
|
| 90 |
+
"usage_instructions": "Choose one action type from the list below. Populate the 'parameters' field in your response strictly according to the 'example_parameters' structure provided.",
|
| 91 |
+
"allowed_actions": [
|
| 92 |
+
{
|
| 93 |
+
"action": "place_settlement",
|
| 94 |
+
"description": "Place your starting settlement on an available node",
|
| 95 |
+
"example_parameters": {
|
| 96 |
+
"node_id": 20,
|
| 97 |
+
"reasoning": "Good resource diversity and probability"
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
]
|
| 101 |
+
}
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
================================================================================
|
| 105 |
+
END OF PROMPT
|
| 106 |
+
================================================================================
|
examples/ai_testing/my_games/prompts/prompt_player_a.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"response_schema": {
|
| 3 |
+
"type": "object",
|
| 4 |
+
"required": [
|
| 5 |
+
"internal_thinking",
|
| 6 |
+
"action"
|
| 7 |
+
],
|
| 8 |
+
"properties": {
|
| 9 |
+
"internal_thinking": {
|
| 10 |
+
"type": "string",
|
| 11 |
+
"description": "Your private reasoning about the situation, strategy, and decision-making process. This is for you only.",
|
| 12 |
+
"minLength": 50
|
| 13 |
+
},
|
| 14 |
+
"note_to_self": {
|
| 15 |
+
"type": "string",
|
| 16 |
+
"description": "A note to remember for next turn. What are you waiting for? What's your plan?"
|
| 17 |
+
},
|
| 18 |
+
"say_outloud": {
|
| 19 |
+
"type": "string",
|
| 20 |
+
"description": "What you want to say to other players (chat message). Use this for negotiation, threats, or table talk."
|
| 21 |
+
},
|
| 22 |
+
"action": {
|
| 23 |
+
"type": "object",
|
| 24 |
+
"required": [
|
| 25 |
+
"type",
|
| 26 |
+
"parameters"
|
| 27 |
+
],
|
| 28 |
+
"properties": {
|
| 29 |
+
"type": {
|
| 30 |
+
"type": "string",
|
| 31 |
+
"description": "The action type (must match one from allowed_actions in constraints)"
|
| 32 |
+
},
|
| 33 |
+
"parameters": {
|
| 34 |
+
"type": "object",
|
| 35 |
+
"description": "Action-specific parameters. If no parameters are needed, provide an empty object.",
|
| 36 |
+
"properties": {
|
| 37 |
+
"target": {
|
| 38 |
+
"type": "string",
|
| 39 |
+
"description": "The target of the action (if applicable)"
|
| 40 |
+
},
|
| 41 |
+
"amount": {
|
| 42 |
+
"type": "number",
|
| 43 |
+
"description": "The amount (if applicable)"
|
| 44 |
+
},
|
| 45 |
+
"location": {
|
| 46 |
+
"type": "string",
|
| 47 |
+
"description": "The location (if applicable)"
|
| 48 |
+
}
|
| 49 |
+
}
|
| 50 |
+
}
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
}
|
| 54 |
+
},
|
| 55 |
+
"system_instruction": "You are an expert Settlers of Catan player. Analyze the game state carefully and respond with your chosen action in the exact JSON format specified in response_schema.",
|
| 56 |
+
"prompt": {
|
| 57 |
+
"meta_data": {
|
| 58 |
+
"agent_name": "a",
|
| 59 |
+
"my_color": "Red",
|
| 60 |
+
"role": "You are player 'a' (Red). Play strategically to win."
|
| 61 |
+
},
|
| 62 |
+
"task_context": {
|
| 63 |
+
"what_just_happened": "It's your turn in the setup phase. Place your first settlement.",
|
| 64 |
+
"instructions": "Analyze the game state and select the optimal move from 'allowed_actions'. Only one action is currently available."
|
| 65 |
+
},
|
| 66 |
+
"game_state": "\n 1. LOOKUP TABLES:\n • \"H\" (Hexes): Array where Index = HexID. Value = Resource+Num.\n Example: H[1]=\"W12\" -> Hex 1 is Wood 12.\n • \"N\" (Nodes): Array where Index = NodeID.\n Format: [ [Neighbors], [HexIDs], Port? ]\n Logic: To find yield of Node 10, check N[10]. Get HexIDs (e.g. [1,5]). Look up H[1] and H[5].\n\n2. CODES: W=Wood, B=Brick, S=Sheep, Wh=Wheat, O=Ore, D=Desert.\n ?3=Any 3:1 port, X2=Specific Resource 2:1 port.\n\n3. STATE: \"bld\"=[NodeID, Owner, Type], \"rds\"=[[From,To], Owner].\n\n4. PLAYERS: \"res\"={Resource:Count}, \"dev\"={\"h\":[Hidden Cards], \"r\":[Revealed] (K=Knight)}, \n \"stat\"=[\"LR\" (Longest Road), \"LA\" (Largest Army)].\n\n5. ROBBER: Located at HexID specified in \"meta.robber\". H[id] is blocked.\n\nJSON:\n{\"meta\":{\"curr\":\"a\",\"phase\":\"SETUP_FIRST_ROUND\",\"robber\":10,\"dice\":null},\"H\":[\"\",\"W12\",\"S5\",\"W4\",\"S8\",\"B6\",\"W3\",\"Wh8\",\"B10\",\"W11\",\"D\",\"O3\",\"S4\",\"B10\",\"Wh9\",\"Wh6\",\"S11\",\"O5\",\"Wh9\",\"O2\"],\"N\":[null,[[2,9],[1]],[[1,3],[1],\"Wh2\"],[[2,4,11],[2,1],\"Wh2\"],[[3,5],[2]],[[4,6,13],[3,2]],[[5,7],[3],\"B2\"],[[6,15],[3],\"B2\"],[[9,18],[4],\"?3\"],[[8,10,1],[4,1],\"?3\"],[[9,11,20],[5,4,1]],[[10,12,3],[5,2,1]],[[11,13,22],[6,5,2]],[[12,14,5],[6,3,2]],[[13,15,24],[7,6,3]],[[14,16,7],[7,3]],[[15,26],[7],\"O2\"],[[18,28],[8],\"S2\"],[[17,19,8],[8,4]],[[18,20,30],[9,8,4]],[[19,21,10],[9,5,4]],[[20,22,32],[10,9,5]],[[21,23,12],[10,6,5]],[[22,24,34],[11,10,6]],[[23,25,14],[11,7,6]],[[24,26,36],[12,11,7]],[[25,27,16],[12,7],\"O2\"],[[26,38],[12]],[[29,17],[8],\"S2\"],[[28,30,39],[13,8]],[[29,31,19],[13,9,8]],[[30,32,41],[14,13,9]],[[31,33,21],[14,10,9]],[[32,34,43],[15,14,10]],[[33,35,23],[15,11,10]],[[34,36,45],[16,15,11]],[[35,37,25],[16,12,11]],[[36,38,47],[16,12],\"?3\"],[[37,27],[12],\"?3\"],[[40,29],[13]],[[39,41,48],[17,13],\"W2\"],[[40,42,31],[17,14,13]],[[41,43,50],[18,17,14]],[[42,44,33],[18,15,14]],[[43,45,52],[19,18,15]],[[44,46,35],[19,16,15]],[[45,47,54],[19,16]],[[46,37],[16]],[[49,40],[17],\"W2\"],[[48,50],[17]],[[49,51,42],[18,17],\"?3\"],[[50,52],[18],\"?3\"],[[51,53,44],[19,18]],[[52,54],[19],\"?3\"],[[53,46],[19],\"?3\"]],\"state\":{\"bld\":[[20,\"a\",\"S\"]],\"rds\":[]},\"players\":{\"a\":{\"vp\":1,\"res\":{}},\"b\":{\"vp\":0,\"res\":{}},\"c\":{\"vp\":0,\"res\":{}}}}",
|
| 67 |
+
"constraints": {
|
| 68 |
+
"usage_instructions": "Choose one action type from the list below. Populate the 'parameters' field in your response strictly according to the 'example_parameters' structure provided.",
|
| 69 |
+
"allowed_actions": [
|
| 70 |
+
{
|
| 71 |
+
"action": "place_settlement",
|
| 72 |
+
"description": "Place your starting settlement on an available node",
|
| 73 |
+
"example_parameters": {
|
| 74 |
+
"node_id": 20,
|
| 75 |
+
"reasoning": "Good resource diversity and probability"
|
| 76 |
+
}
|
| 77 |
+
}
|
| 78 |
+
]
|
| 79 |
+
}
|
| 80 |
+
}
|
| 81 |
+
}
|
examples/ai_testing/my_games/prompts/prompt_player_a.txt
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
================================================================================
|
| 2 |
+
AI AGENT PROMPT - PLAYER A
|
| 3 |
+
Generated: 2026-01-03 20:37:23
|
| 4 |
+
================================================================================
|
| 5 |
+
|
| 6 |
+
📋 RESPONSE SCHEMA (Expected LLM Output Format)
|
| 7 |
+
--------------------------------------------------------------------------------
|
| 8 |
+
{
|
| 9 |
+
"type": "object",
|
| 10 |
+
"required": [
|
| 11 |
+
"internal_thinking",
|
| 12 |
+
"action"
|
| 13 |
+
],
|
| 14 |
+
"properties": {
|
| 15 |
+
"internal_thinking": {
|
| 16 |
+
"type": "string",
|
| 17 |
+
"description": "Your private reasoning about the situation, strategy, and decision-making process. This is for you only.",
|
| 18 |
+
"minLength": 50
|
| 19 |
+
},
|
| 20 |
+
"note_to_self": {
|
| 21 |
+
"type": "string",
|
| 22 |
+
"description": "A note to remember for next turn. What are you waiting for? What's your plan?"
|
| 23 |
+
},
|
| 24 |
+
"say_outloud": {
|
| 25 |
+
"type": "string",
|
| 26 |
+
"description": "What you want to say to other players (chat message). Use this for negotiation, threats, or table talk."
|
| 27 |
+
},
|
| 28 |
+
"action": {
|
| 29 |
+
"type": "object",
|
| 30 |
+
"required": [
|
| 31 |
+
"type",
|
| 32 |
+
"parameters"
|
| 33 |
+
],
|
| 34 |
+
"properties": {
|
| 35 |
+
"type": {
|
| 36 |
+
"type": "string",
|
| 37 |
+
"description": "The action type (must match one from allowed_actions in constraints)"
|
| 38 |
+
},
|
| 39 |
+
"parameters": {
|
| 40 |
+
"type": "object",
|
| 41 |
+
"description": "Action-specific parameters. If no parameters are needed, provide an empty object.",
|
| 42 |
+
"properties": {
|
| 43 |
+
"target": {
|
| 44 |
+
"type": "string",
|
| 45 |
+
"description": "The target of the action (if applicable)"
|
| 46 |
+
},
|
| 47 |
+
"amount": {
|
| 48 |
+
"type": "number",
|
| 49 |
+
"description": "The amount (if applicable)"
|
| 50 |
+
},
|
| 51 |
+
"location": {
|
| 52 |
+
"type": "string",
|
| 53 |
+
"description": "The location (if applicable)"
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
}
|
| 57 |
+
}
|
| 58 |
+
}
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
================================================================================
|
| 63 |
+
📨 PROMPT TO SEND TO LLM
|
| 64 |
+
================================================================================
|
| 65 |
+
|
| 66 |
+
{
|
| 67 |
+
"meta_data": {
|
| 68 |
+
"agent_name": "a",
|
| 69 |
+
"my_color": "Red",
|
| 70 |
+
"role": "You are player 'a' (Red). Play strategically to win."
|
| 71 |
+
},
|
| 72 |
+
"task_context": {
|
| 73 |
+
"what_just_happened": "It's your turn in the setup phase. Place your first settlement.",
|
| 74 |
+
"instructions": "Analyze the game state and select the optimal move from 'allowed_actions'. Only one action is currently available."
|
| 75 |
+
},
|
| 76 |
+
"game_state": "\n 1. LOOKUP TABLES:\n • \"H\" (Hexes): Array where Index = HexID. Value = Resource+Num.\n Example: H[1]=\"W12\" -> Hex 1 is Wood 12.\n • \"N\" (Nodes): Array where Index = NodeID.\n Format: [ [Neighbors], [HexIDs], Port? ]\n Logic: To find yield of Node 10, check N[10]. Get HexIDs (e.g. [1,5]). Look up H[1] and H[5].\n\n2. CODES: W=Wood, B=Brick, S=Sheep, Wh=Wheat, O=Ore, D=Desert.\n ?3=Any 3:1 port, X2=Specific Resource 2:1 port.\n\n3. STATE: \"bld\"=[NodeID, Owner, Type], \"rds\"=[[From,To], Owner].\n\n4. PLAYERS: \"res\"={Resource:Count}, \"dev\"={\"h\":[Hidden Cards], \"r\":[Revealed] (K=Knight)}, \n \"stat\"=[\"LR\" (Longest Road), \"LA\" (Largest Army)].\n\n5. ROBBER: Located at HexID specified in \"meta.robber\". H[id] is blocked.\n\nJSON:\n{\"meta\":{\"curr\":\"a\",\"phase\":\"SETUP_FIRST_ROUND\",\"robber\":10,\"dice\":null},\"H\":[\"\",\"W12\",\"S5\",\"W4\",\"S8\",\"B6\",\"W3\",\"Wh8\",\"B10\",\"W11\",\"D\",\"O3\",\"S4\",\"B10\",\"Wh9\",\"Wh6\",\"S11\",\"O5\",\"Wh9\",\"O2\"],\"N\":[null,[[2,9],[1]],[[1,3],[1],\"Wh2\"],[[2,4,11],[2,1],\"Wh2\"],[[3,5],[2]],[[4,6,13],[3,2]],[[5,7],[3],\"B2\"],[[6,15],[3],\"B2\"],[[9,18],[4],\"?3\"],[[8,10,1],[4,1],\"?3\"],[[9,11,20],[5,4,1]],[[10,12,3],[5,2,1]],[[11,13,22],[6,5,2]],[[12,14,5],[6,3,2]],[[13,15,24],[7,6,3]],[[14,16,7],[7,3]],[[15,26],[7],\"O2\"],[[18,28],[8],\"S2\"],[[17,19,8],[8,4]],[[18,20,30],[9,8,4]],[[19,21,10],[9,5,4]],[[20,22,32],[10,9,5]],[[21,23,12],[10,6,5]],[[22,24,34],[11,10,6]],[[23,25,14],[11,7,6]],[[24,26,36],[12,11,7]],[[25,27,16],[12,7],\"O2\"],[[26,38],[12]],[[29,17],[8],\"S2\"],[[28,30,39],[13,8]],[[29,31,19],[13,9,8]],[[30,32,41],[14,13,9]],[[31,33,21],[14,10,9]],[[32,34,43],[15,14,10]],[[33,35,23],[15,11,10]],[[34,36,45],[16,15,11]],[[35,37,25],[16,12,11]],[[36,38,47],[16,12],\"?3\"],[[37,27],[12],\"?3\"],[[40,29],[13]],[[39,41,48],[17,13],\"W2\"],[[40,42,31],[17,14,13]],[[41,43,50],[18,17,14]],[[42,44,33],[18,15,14]],[[43,45,52],[19,18,15]],[[44,46,35],[19,16,15]],[[45,47,54],[19,16]],[[46,37],[16]],[[49,40],[17],\"W2\"],[[48,50],[17]],[[49,51,42],[18,17],\"?3\"],[[50,52],[18],\"?3\"],[[51,53,44],[19,18]],[[52,54],[19],\"?3\"],[[53,46],[19],\"?3\"]],\"state\":{\"bld\":[[20,\"a\",\"S\"]],\"rds\":[]},\"players\":{\"a\":{\"vp\":1,\"res\":{}},\"b\":{\"vp\":0,\"res\":{}},\"c\":{\"vp\":0,\"res\":{}}}}",
|
| 77 |
+
"constraints": {
|
| 78 |
+
"usage_instructions": "Choose one action type from the list below. Populate the 'parameters' field in your response strictly according to the 'example_parameters' structure provided.",
|
| 79 |
+
"allowed_actions": [
|
| 80 |
+
{
|
| 81 |
+
"action": "place_settlement",
|
| 82 |
+
"description": "Place your starting settlement on an available node",
|
| 83 |
+
"example_parameters": {
|
| 84 |
+
"node_id": 20,
|
| 85 |
+
"reasoning": "Good resource diversity and probability"
|
| 86 |
+
}
|
| 87 |
+
}
|
| 88 |
+
]
|
| 89 |
+
}
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
================================================================================
|
| 93 |
+
END OF PROMPT
|
| 94 |
+
================================================================================
|
examples/ai_testing/my_games/prompts/prompt_player_b.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"response_schema": {
|
| 3 |
+
"type": "object",
|
| 4 |
+
"required": [
|
| 5 |
+
"internal_thinking",
|
| 6 |
+
"action"
|
| 7 |
+
],
|
| 8 |
+
"properties": {
|
| 9 |
+
"internal_thinking": {
|
| 10 |
+
"type": "string",
|
| 11 |
+
"description": "Your private reasoning about the situation, strategy, and decision-making process. This is for you only.",
|
| 12 |
+
"minLength": 50
|
| 13 |
+
},
|
| 14 |
+
"note_to_self": {
|
| 15 |
+
"type": "string",
|
| 16 |
+
"description": "A note to remember for next turn. What are you waiting for? What's your plan?"
|
| 17 |
+
},
|
| 18 |
+
"say_outloud": {
|
| 19 |
+
"type": "string",
|
| 20 |
+
"description": "What you want to say to other players (chat message). Use this for negotiation, threats, or table talk."
|
| 21 |
+
},
|
| 22 |
+
"action": {
|
| 23 |
+
"type": "object",
|
| 24 |
+
"required": [
|
| 25 |
+
"type",
|
| 26 |
+
"parameters"
|
| 27 |
+
],
|
| 28 |
+
"properties": {
|
| 29 |
+
"type": {
|
| 30 |
+
"type": "string",
|
| 31 |
+
"description": "The action type (must match one from allowed_actions in constraints)"
|
| 32 |
+
},
|
| 33 |
+
"parameters": {
|
| 34 |
+
"type": "object",
|
| 35 |
+
"description": "Action-specific parameters. If no parameters are needed, provide an empty object.",
|
| 36 |
+
"properties": {
|
| 37 |
+
"target": {
|
| 38 |
+
"type": "string",
|
| 39 |
+
"description": "The target of the action (if applicable)"
|
| 40 |
+
},
|
| 41 |
+
"amount": {
|
| 42 |
+
"type": "number",
|
| 43 |
+
"description": "The amount (if applicable)"
|
| 44 |
+
},
|
| 45 |
+
"location": {
|
| 46 |
+
"type": "string",
|
| 47 |
+
"description": "The location (if applicable)"
|
| 48 |
+
}
|
| 49 |
+
}
|
| 50 |
+
}
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
}
|
| 54 |
+
},
|
| 55 |
+
"system_instruction": "You are an expert Settlers of Catan player. Analyze the game state carefully and respond with your chosen action in the exact JSON format specified in response_schema.",
|
| 56 |
+
"prompt": {
|
| 57 |
+
"meta_data": {
|
| 58 |
+
"agent_name": "b",
|
| 59 |
+
"my_color": "Blue",
|
| 60 |
+
"role": "You are player 'b' (Blue). Play strategically to win."
|
| 61 |
+
},
|
| 62 |
+
"task_context": {
|
| 63 |
+
"what_just_happened": "It's a's turn to place their first settlement.",
|
| 64 |
+
"instructions": "Analyze the game state and select the optimal move from 'allowed_actions'. Consider all strategic implications before deciding."
|
| 65 |
+
},
|
| 66 |
+
"game_state": "\n 1. LOOKUP TABLES:\n • \"H\" (Hexes): Array where Index = HexID. Value = Resource+Num.\n Example: H[1]=\"W12\" -> Hex 1 is Wood 12.\n • \"N\" (Nodes): Array where Index = NodeID.\n Format: [ [Neighbors], [HexIDs], Port? ]\n Logic: To find yield of Node 10, check N[10]. Get HexIDs (e.g. [1,5]). Look up H[1] and H[5].\n\n2. CODES: W=Wood, B=Brick, S=Sheep, Wh=Wheat, O=Ore, D=Desert.\n ?3=Any 3:1 port, X2=Specific Resource 2:1 port.\n\n3. STATE: \"bld\"=[NodeID, Owner, Type], \"rds\"=[[From,To], Owner].\n\n4. PLAYERS: \"res\"={Resource:Count}, \"dev\"={\"h\":[Hidden Cards], \"r\":[Revealed] (K=Knight)}, \n \"stat\"=[\"LR\" (Longest Road), \"LA\" (Largest Army)].\n\n5. ROBBER: Located at HexID specified in \"meta.robber\". H[id] is blocked.\n\nJSON:\n{\"meta\":{\"curr\":\"a\",\"phase\":\"SETUP_FIRST_ROUND\",\"robber\":10,\"dice\":null},\"H\":[\"\",\"W12\",\"S5\",\"W4\",\"S8\",\"B6\",\"W3\",\"Wh8\",\"B10\",\"W11\",\"D\",\"O3\",\"S4\",\"B10\",\"Wh9\",\"Wh6\",\"S11\",\"O5\",\"Wh9\",\"O2\"],\"N\":[null,[[2,9],[1]],[[1,3],[1],\"Wh2\"],[[2,4,11],[2,1],\"Wh2\"],[[3,5],[2]],[[4,6,13],[3,2]],[[5,7],[3],\"B2\"],[[6,15],[3],\"B2\"],[[9,18],[4],\"?3\"],[[8,10,1],[4,1],\"?3\"],[[9,11,20],[5,4,1]],[[10,12,3],[5,2,1]],[[11,13,22],[6,5,2]],[[12,14,5],[6,3,2]],[[13,15,24],[7,6,3]],[[14,16,7],[7,3]],[[15,26],[7],\"O2\"],[[18,28],[8],\"S2\"],[[17,19,8],[8,4]],[[18,20,30],[9,8,4]],[[19,21,10],[9,5,4]],[[20,22,32],[10,9,5]],[[21,23,12],[10,6,5]],[[22,24,34],[11,10,6]],[[23,25,14],[11,7,6]],[[24,26,36],[12,11,7]],[[25,27,16],[12,7],\"O2\"],[[26,38],[12]],[[29,17],[8],\"S2\"],[[28,30,39],[13,8]],[[29,31,19],[13,9,8]],[[30,32,41],[14,13,9]],[[31,33,21],[14,10,9]],[[32,34,43],[15,14,10]],[[33,35,23],[15,11,10]],[[34,36,45],[16,15,11]],[[35,37,25],[16,12,11]],[[36,38,47],[16,12],\"?3\"],[[37,27],[12],\"?3\"],[[40,29],[13]],[[39,41,48],[17,13],\"W2\"],[[40,42,31],[17,14,13]],[[41,43,50],[18,17,14]],[[42,44,33],[18,15,14]],[[43,45,52],[19,18,15]],[[44,46,35],[19,16,15]],[[45,47,54],[19,16]],[[46,37],[16]],[[49,40],[17],\"W2\"],[[48,50],[17]],[[49,51,42],[18,17],\"?3\"],[[50,52],[18],\"?3\"],[[51,53,44],[19,18]],[[52,54],[19],\"?3\"],[[53,46],[19],\"?3\"]],\"state\":{\"bld\":[[20,\"a\",\"S\"]],\"rds\":[]},\"players\":{\"a\":{\"vp\":1,\"res\":{}},\"b\":{\"vp\":0,\"res\":{}},\"c\":{\"vp\":0,\"res\":{}}}}"
|
| 67 |
+
}
|
| 68 |
+
}
|
examples/ai_testing/my_games/prompts/prompt_player_b.txt
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
================================================================================
|
| 2 |
+
AI AGENT PROMPT - PLAYER B
|
| 3 |
+
Generated: 2026-01-03 20:37:23
|
| 4 |
+
================================================================================
|
| 5 |
+
|
| 6 |
+
📋 RESPONSE SCHEMA (Expected LLM Output Format)
|
| 7 |
+
--------------------------------------------------------------------------------
|
| 8 |
+
{
|
| 9 |
+
"type": "object",
|
| 10 |
+
"required": [
|
| 11 |
+
"internal_thinking",
|
| 12 |
+
"action"
|
| 13 |
+
],
|
| 14 |
+
"properties": {
|
| 15 |
+
"internal_thinking": {
|
| 16 |
+
"type": "string",
|
| 17 |
+
"description": "Your private reasoning about the situation, strategy, and decision-making process. This is for you only.",
|
| 18 |
+
"minLength": 50
|
| 19 |
+
},
|
| 20 |
+
"note_to_self": {
|
| 21 |
+
"type": "string",
|
| 22 |
+
"description": "A note to remember for next turn. What are you waiting for? What's your plan?"
|
| 23 |
+
},
|
| 24 |
+
"say_outloud": {
|
| 25 |
+
"type": "string",
|
| 26 |
+
"description": "What you want to say to other players (chat message). Use this for negotiation, threats, or table talk."
|
| 27 |
+
},
|
| 28 |
+
"action": {
|
| 29 |
+
"type": "object",
|
| 30 |
+
"required": [
|
| 31 |
+
"type",
|
| 32 |
+
"parameters"
|
| 33 |
+
],
|
| 34 |
+
"properties": {
|
| 35 |
+
"type": {
|
| 36 |
+
"type": "string",
|
| 37 |
+
"description": "The action type (must match one from allowed_actions in constraints)"
|
| 38 |
+
},
|
| 39 |
+
"parameters": {
|
| 40 |
+
"type": "object",
|
| 41 |
+
"description": "Action-specific parameters. If no parameters are needed, provide an empty object.",
|
| 42 |
+
"properties": {
|
| 43 |
+
"target": {
|
| 44 |
+
"type": "string",
|
| 45 |
+
"description": "The target of the action (if applicable)"
|
| 46 |
+
},
|
| 47 |
+
"amount": {
|
| 48 |
+
"type": "number",
|
| 49 |
+
"description": "The amount (if applicable)"
|
| 50 |
+
},
|
| 51 |
+
"location": {
|
| 52 |
+
"type": "string",
|
| 53 |
+
"description": "The location (if applicable)"
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
}
|
| 57 |
+
}
|
| 58 |
+
}
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
================================================================================
|
| 63 |
+
📨 PROMPT TO SEND TO LLM
|
| 64 |
+
================================================================================
|
| 65 |
+
|
| 66 |
+
{
|
| 67 |
+
"meta_data": {
|
| 68 |
+
"agent_name": "b",
|
| 69 |
+
"my_color": "Blue",
|
| 70 |
+
"role": "You are player 'b' (Blue). Play strategically to win."
|
| 71 |
+
},
|
| 72 |
+
"task_context": {
|
| 73 |
+
"what_just_happened": "It's a's turn to place their first settlement.",
|
| 74 |
+
"instructions": "Analyze the game state and select the optimal move from 'allowed_actions'. Consider all strategic implications before deciding."
|
| 75 |
+
},
|
| 76 |
+
"game_state": "\n 1. LOOKUP TABLES:\n • \"H\" (Hexes): Array where Index = HexID. Value = Resource+Num.\n Example: H[1]=\"W12\" -> Hex 1 is Wood 12.\n • \"N\" (Nodes): Array where Index = NodeID.\n Format: [ [Neighbors], [HexIDs], Port? ]\n Logic: To find yield of Node 10, check N[10]. Get HexIDs (e.g. [1,5]). Look up H[1] and H[5].\n\n2. CODES: W=Wood, B=Brick, S=Sheep, Wh=Wheat, O=Ore, D=Desert.\n ?3=Any 3:1 port, X2=Specific Resource 2:1 port.\n\n3. STATE: \"bld\"=[NodeID, Owner, Type], \"rds\"=[[From,To], Owner].\n\n4. PLAYERS: \"res\"={Resource:Count}, \"dev\"={\"h\":[Hidden Cards], \"r\":[Revealed] (K=Knight)}, \n \"stat\"=[\"LR\" (Longest Road), \"LA\" (Largest Army)].\n\n5. ROBBER: Located at HexID specified in \"meta.robber\". H[id] is blocked.\n\nJSON:\n{\"meta\":{\"curr\":\"a\",\"phase\":\"SETUP_FIRST_ROUND\",\"robber\":10,\"dice\":null},\"H\":[\"\",\"W12\",\"S5\",\"W4\",\"S8\",\"B6\",\"W3\",\"Wh8\",\"B10\",\"W11\",\"D\",\"O3\",\"S4\",\"B10\",\"Wh9\",\"Wh6\",\"S11\",\"O5\",\"Wh9\",\"O2\"],\"N\":[null,[[2,9],[1]],[[1,3],[1],\"Wh2\"],[[2,4,11],[2,1],\"Wh2\"],[[3,5],[2]],[[4,6,13],[3,2]],[[5,7],[3],\"B2\"],[[6,15],[3],\"B2\"],[[9,18],[4],\"?3\"],[[8,10,1],[4,1],\"?3\"],[[9,11,20],[5,4,1]],[[10,12,3],[5,2,1]],[[11,13,22],[6,5,2]],[[12,14,5],[6,3,2]],[[13,15,24],[7,6,3]],[[14,16,7],[7,3]],[[15,26],[7],\"O2\"],[[18,28],[8],\"S2\"],[[17,19,8],[8,4]],[[18,20,30],[9,8,4]],[[19,21,10],[9,5,4]],[[20,22,32],[10,9,5]],[[21,23,12],[10,6,5]],[[22,24,34],[11,10,6]],[[23,25,14],[11,7,6]],[[24,26,36],[12,11,7]],[[25,27,16],[12,7],\"O2\"],[[26,38],[12]],[[29,17],[8],\"S2\"],[[28,30,39],[13,8]],[[29,31,19],[13,9,8]],[[30,32,41],[14,13,9]],[[31,33,21],[14,10,9]],[[32,34,43],[15,14,10]],[[33,35,23],[15,11,10]],[[34,36,45],[16,15,11]],[[35,37,25],[16,12,11]],[[36,38,47],[16,12],\"?3\"],[[37,27],[12],\"?3\"],[[40,29],[13]],[[39,41,48],[17,13],\"W2\"],[[40,42,31],[17,14,13]],[[41,43,50],[18,17,14]],[[42,44,33],[18,15,14]],[[43,45,52],[19,18,15]],[[44,46,35],[19,16,15]],[[45,47,54],[19,16]],[[46,37],[16]],[[49,40],[17],\"W2\"],[[48,50],[17]],[[49,51,42],[18,17],\"?3\"],[[50,52],[18],\"?3\"],[[51,53,44],[19,18]],[[52,54],[19],\"?3\"],[[53,46],[19],\"?3\"]],\"state\":{\"bld\":[[20,\"a\",\"S\"]],\"rds\":[]},\"players\":{\"a\":{\"vp\":1,\"res\":{}},\"b\":{\"vp\":0,\"res\":{}},\"c\":{\"vp\":0,\"res\":{}}}}"
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
================================================================================
|
| 80 |
+
END OF PROMPT
|
| 81 |
+
================================================================================
|
examples/ai_testing/my_games/prompts/prompt_player_c.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"response_schema": {
|
| 3 |
+
"type": "object",
|
| 4 |
+
"required": [
|
| 5 |
+
"internal_thinking",
|
| 6 |
+
"action"
|
| 7 |
+
],
|
| 8 |
+
"properties": {
|
| 9 |
+
"internal_thinking": {
|
| 10 |
+
"type": "string",
|
| 11 |
+
"description": "Your private reasoning about the situation, strategy, and decision-making process. This is for you only.",
|
| 12 |
+
"minLength": 50
|
| 13 |
+
},
|
| 14 |
+
"note_to_self": {
|
| 15 |
+
"type": "string",
|
| 16 |
+
"description": "A note to remember for next turn. What are you waiting for? What's your plan?"
|
| 17 |
+
},
|
| 18 |
+
"say_outloud": {
|
| 19 |
+
"type": "string",
|
| 20 |
+
"description": "What you want to say to other players (chat message). Use this for negotiation, threats, or table talk."
|
| 21 |
+
},
|
| 22 |
+
"action": {
|
| 23 |
+
"type": "object",
|
| 24 |
+
"required": [
|
| 25 |
+
"type",
|
| 26 |
+
"parameters"
|
| 27 |
+
],
|
| 28 |
+
"properties": {
|
| 29 |
+
"type": {
|
| 30 |
+
"type": "string",
|
| 31 |
+
"description": "The action type (must match one from allowed_actions in constraints)"
|
| 32 |
+
},
|
| 33 |
+
"parameters": {
|
| 34 |
+
"type": "object",
|
| 35 |
+
"description": "Action-specific parameters. If no parameters are needed, provide an empty object.",
|
| 36 |
+
"properties": {
|
| 37 |
+
"target": {
|
| 38 |
+
"type": "string",
|
| 39 |
+
"description": "The target of the action (if applicable)"
|
| 40 |
+
},
|
| 41 |
+
"amount": {
|
| 42 |
+
"type": "number",
|
| 43 |
+
"description": "The amount (if applicable)"
|
| 44 |
+
},
|
| 45 |
+
"location": {
|
| 46 |
+
"type": "string",
|
| 47 |
+
"description": "The location (if applicable)"
|
| 48 |
+
}
|
| 49 |
+
}
|
| 50 |
+
}
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
}
|
| 54 |
+
},
|
| 55 |
+
"system_instruction": "You are an expert Settlers of Catan player. Analyze the game state carefully and respond with your chosen action in the exact JSON format specified in response_schema.",
|
| 56 |
+
"prompt": {
|
| 57 |
+
"meta_data": {
|
| 58 |
+
"agent_name": "c",
|
| 59 |
+
"my_color": "White",
|
| 60 |
+
"role": "You are player 'c' (White). Play strategically to win."
|
| 61 |
+
},
|
| 62 |
+
"task_context": {
|
| 63 |
+
"what_just_happened": "It's a's turn to place their first settlement.",
|
| 64 |
+
"instructions": "Analyze the game state and select the optimal move from 'allowed_actions'. Consider all strategic implications before deciding."
|
| 65 |
+
},
|
| 66 |
+
"game_state": "\n 1. LOOKUP TABLES:\n • \"H\" (Hexes): Array where Index = HexID. Value = Resource+Num.\n Example: H[1]=\"W12\" -> Hex 1 is Wood 12.\n • \"N\" (Nodes): Array where Index = NodeID.\n Format: [ [Neighbors], [HexIDs], Port? ]\n Logic: To find yield of Node 10, check N[10]. Get HexIDs (e.g. [1,5]). Look up H[1] and H[5].\n\n2. CODES: W=Wood, B=Brick, S=Sheep, Wh=Wheat, O=Ore, D=Desert.\n ?3=Any 3:1 port, X2=Specific Resource 2:1 port.\n\n3. STATE: \"bld\"=[NodeID, Owner, Type], \"rds\"=[[From,To], Owner].\n\n4. PLAYERS: \"res\"={Resource:Count}, \"dev\"={\"h\":[Hidden Cards], \"r\":[Revealed] (K=Knight)}, \n \"stat\"=[\"LR\" (Longest Road), \"LA\" (Largest Army)].\n\n5. ROBBER: Located at HexID specified in \"meta.robber\". H[id] is blocked.\n\nJSON:\n{\"meta\":{\"curr\":\"a\",\"phase\":\"SETUP_FIRST_ROUND\",\"robber\":10,\"dice\":null},\"H\":[\"\",\"W12\",\"S5\",\"W4\",\"S8\",\"B6\",\"W3\",\"Wh8\",\"B10\",\"W11\",\"D\",\"O3\",\"S4\",\"B10\",\"Wh9\",\"Wh6\",\"S11\",\"O5\",\"Wh9\",\"O2\"],\"N\":[null,[[2,9],[1]],[[1,3],[1],\"Wh2\"],[[2,4,11],[2,1],\"Wh2\"],[[3,5],[2]],[[4,6,13],[3,2]],[[5,7],[3],\"B2\"],[[6,15],[3],\"B2\"],[[9,18],[4],\"?3\"],[[8,10,1],[4,1],\"?3\"],[[9,11,20],[5,4,1]],[[10,12,3],[5,2,1]],[[11,13,22],[6,5,2]],[[12,14,5],[6,3,2]],[[13,15,24],[7,6,3]],[[14,16,7],[7,3]],[[15,26],[7],\"O2\"],[[18,28],[8],\"S2\"],[[17,19,8],[8,4]],[[18,20,30],[9,8,4]],[[19,21,10],[9,5,4]],[[20,22,32],[10,9,5]],[[21,23,12],[10,6,5]],[[22,24,34],[11,10,6]],[[23,25,14],[11,7,6]],[[24,26,36],[12,11,7]],[[25,27,16],[12,7],\"O2\"],[[26,38],[12]],[[29,17],[8],\"S2\"],[[28,30,39],[13,8]],[[29,31,19],[13,9,8]],[[30,32,41],[14,13,9]],[[31,33,21],[14,10,9]],[[32,34,43],[15,14,10]],[[33,35,23],[15,11,10]],[[34,36,45],[16,15,11]],[[35,37,25],[16,12,11]],[[36,38,47],[16,12],\"?3\"],[[37,27],[12],\"?3\"],[[40,29],[13]],[[39,41,48],[17,13],\"W2\"],[[40,42,31],[17,14,13]],[[41,43,50],[18,17,14]],[[42,44,33],[18,15,14]],[[43,45,52],[19,18,15]],[[44,46,35],[19,16,15]],[[45,47,54],[19,16]],[[46,37],[16]],[[49,40],[17],\"W2\"],[[48,50],[17]],[[49,51,42],[18,17],\"?3\"],[[50,52],[18],\"?3\"],[[51,53,44],[19,18]],[[52,54],[19],\"?3\"],[[53,46],[19],\"?3\"]],\"state\":{\"bld\":[[20,\"a\",\"S\"]],\"rds\":[]},\"players\":{\"a\":{\"vp\":1,\"res\":{}},\"b\":{\"vp\":0,\"res\":{}},\"c\":{\"vp\":0,\"res\":{}}}}"
|
| 67 |
+
}
|
| 68 |
+
}
|
examples/ai_testing/my_games/prompts/prompt_player_c.txt
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
================================================================================
|
| 2 |
+
AI AGENT PROMPT - PLAYER C
|
| 3 |
+
Generated: 2026-01-03 20:37:23
|
| 4 |
+
================================================================================
|
| 5 |
+
|
| 6 |
+
📋 RESPONSE SCHEMA (Expected LLM Output Format)
|
| 7 |
+
--------------------------------------------------------------------------------
|
| 8 |
+
{
|
| 9 |
+
"type": "object",
|
| 10 |
+
"required": [
|
| 11 |
+
"internal_thinking",
|
| 12 |
+
"action"
|
| 13 |
+
],
|
| 14 |
+
"properties": {
|
| 15 |
+
"internal_thinking": {
|
| 16 |
+
"type": "string",
|
| 17 |
+
"description": "Your private reasoning about the situation, strategy, and decision-making process. This is for you only.",
|
| 18 |
+
"minLength": 50
|
| 19 |
+
},
|
| 20 |
+
"note_to_self": {
|
| 21 |
+
"type": "string",
|
| 22 |
+
"description": "A note to remember for next turn. What are you waiting for? What's your plan?"
|
| 23 |
+
},
|
| 24 |
+
"say_outloud": {
|
| 25 |
+
"type": "string",
|
| 26 |
+
"description": "What you want to say to other players (chat message). Use this for negotiation, threats, or table talk."
|
| 27 |
+
},
|
| 28 |
+
"action": {
|
| 29 |
+
"type": "object",
|
| 30 |
+
"required": [
|
| 31 |
+
"type",
|
| 32 |
+
"parameters"
|
| 33 |
+
],
|
| 34 |
+
"properties": {
|
| 35 |
+
"type": {
|
| 36 |
+
"type": "string",
|
| 37 |
+
"description": "The action type (must match one from allowed_actions in constraints)"
|
| 38 |
+
},
|
| 39 |
+
"parameters": {
|
| 40 |
+
"type": "object",
|
| 41 |
+
"description": "Action-specific parameters. If no parameters are needed, provide an empty object.",
|
| 42 |
+
"properties": {
|
| 43 |
+
"target": {
|
| 44 |
+
"type": "string",
|
| 45 |
+
"description": "The target of the action (if applicable)"
|
| 46 |
+
},
|
| 47 |
+
"amount": {
|
| 48 |
+
"type": "number",
|
| 49 |
+
"description": "The amount (if applicable)"
|
| 50 |
+
},
|
| 51 |
+
"location": {
|
| 52 |
+
"type": "string",
|
| 53 |
+
"description": "The location (if applicable)"
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
}
|
| 57 |
+
}
|
| 58 |
+
}
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
================================================================================
|
| 63 |
+
📨 PROMPT TO SEND TO LLM
|
| 64 |
+
================================================================================
|
| 65 |
+
|
| 66 |
+
{
|
| 67 |
+
"meta_data": {
|
| 68 |
+
"agent_name": "c",
|
| 69 |
+
"my_color": "White",
|
| 70 |
+
"role": "You are player 'c' (White). Play strategically to win."
|
| 71 |
+
},
|
| 72 |
+
"task_context": {
|
| 73 |
+
"what_just_happened": "It's a's turn to place their first settlement.",
|
| 74 |
+
"instructions": "Analyze the game state and select the optimal move from 'allowed_actions'. Consider all strategic implications before deciding."
|
| 75 |
+
},
|
| 76 |
+
"game_state": "\n 1. LOOKUP TABLES:\n • \"H\" (Hexes): Array where Index = HexID. Value = Resource+Num.\n Example: H[1]=\"W12\" -> Hex 1 is Wood 12.\n • \"N\" (Nodes): Array where Index = NodeID.\n Format: [ [Neighbors], [HexIDs], Port? ]\n Logic: To find yield of Node 10, check N[10]. Get HexIDs (e.g. [1,5]). Look up H[1] and H[5].\n\n2. CODES: W=Wood, B=Brick, S=Sheep, Wh=Wheat, O=Ore, D=Desert.\n ?3=Any 3:1 port, X2=Specific Resource 2:1 port.\n\n3. STATE: \"bld\"=[NodeID, Owner, Type], \"rds\"=[[From,To], Owner].\n\n4. PLAYERS: \"res\"={Resource:Count}, \"dev\"={\"h\":[Hidden Cards], \"r\":[Revealed] (K=Knight)}, \n \"stat\"=[\"LR\" (Longest Road), \"LA\" (Largest Army)].\n\n5. ROBBER: Located at HexID specified in \"meta.robber\". H[id] is blocked.\n\nJSON:\n{\"meta\":{\"curr\":\"a\",\"phase\":\"SETUP_FIRST_ROUND\",\"robber\":10,\"dice\":null},\"H\":[\"\",\"W12\",\"S5\",\"W4\",\"S8\",\"B6\",\"W3\",\"Wh8\",\"B10\",\"W11\",\"D\",\"O3\",\"S4\",\"B10\",\"Wh9\",\"Wh6\",\"S11\",\"O5\",\"Wh9\",\"O2\"],\"N\":[null,[[2,9],[1]],[[1,3],[1],\"Wh2\"],[[2,4,11],[2,1],\"Wh2\"],[[3,5],[2]],[[4,6,13],[3,2]],[[5,7],[3],\"B2\"],[[6,15],[3],\"B2\"],[[9,18],[4],\"?3\"],[[8,10,1],[4,1],\"?3\"],[[9,11,20],[5,4,1]],[[10,12,3],[5,2,1]],[[11,13,22],[6,5,2]],[[12,14,5],[6,3,2]],[[13,15,24],[7,6,3]],[[14,16,7],[7,3]],[[15,26],[7],\"O2\"],[[18,28],[8],\"S2\"],[[17,19,8],[8,4]],[[18,20,30],[9,8,4]],[[19,21,10],[9,5,4]],[[20,22,32],[10,9,5]],[[21,23,12],[10,6,5]],[[22,24,34],[11,10,6]],[[23,25,14],[11,7,6]],[[24,26,36],[12,11,7]],[[25,27,16],[12,7],\"O2\"],[[26,38],[12]],[[29,17],[8],\"S2\"],[[28,30,39],[13,8]],[[29,31,19],[13,9,8]],[[30,32,41],[14,13,9]],[[31,33,21],[14,10,9]],[[32,34,43],[15,14,10]],[[33,35,23],[15,11,10]],[[34,36,45],[16,15,11]],[[35,37,25],[16,12,11]],[[36,38,47],[16,12],\"?3\"],[[37,27],[12],\"?3\"],[[40,29],[13]],[[39,41,48],[17,13],\"W2\"],[[40,42,31],[17,14,13]],[[41,43,50],[18,17,14]],[[42,44,33],[18,15,14]],[[43,45,52],[19,18,15]],[[44,46,35],[19,16,15]],[[45,47,54],[19,16]],[[46,37],[16]],[[49,40],[17],\"W2\"],[[48,50],[17]],[[49,51,42],[18,17],\"?3\"],[[50,52],[18],\"?3\"],[[51,53,44],[19,18]],[[52,54],[19],\"?3\"],[[53,46],[19],\"?3\"]],\"state\":{\"bld\":[[20,\"a\",\"S\"]],\"rds\":[]},\"players\":{\"a\":{\"vp\":1,\"res\":{}},\"b\":{\"vp\":0,\"res\":{}},\"c\":{\"vp\":0,\"res\":{}}}}"
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
================================================================================
|
| 80 |
+
END OF PROMPT
|
| 81 |
+
================================================================================
|
examples/ai_testing/my_games/test_prompt_format.json
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"response_schema": {
|
| 3 |
+
"type": "object",
|
| 4 |
+
"required": [
|
| 5 |
+
"internal_thinking",
|
| 6 |
+
"action"
|
| 7 |
+
],
|
| 8 |
+
"properties": {
|
| 9 |
+
"internal_thinking": {
|
| 10 |
+
"type": "string",
|
| 11 |
+
"description": "Your private reasoning about the situation, strategy, and decision-making process. This is for you only.",
|
| 12 |
+
"minLength": 50
|
| 13 |
+
},
|
| 14 |
+
"note_to_self": {
|
| 15 |
+
"type": "string",
|
| 16 |
+
"description": "A note to remember for next turn. What are you waiting for? What's your plan?",
|
| 17 |
+
"examples": [
|
| 18 |
+
"Waiting for Red's response on trade",
|
| 19 |
+
"Focus on building toward ore port next",
|
| 20 |
+
"Watch Blue's progress on longest road"
|
| 21 |
+
]
|
| 22 |
+
},
|
| 23 |
+
"say_outloud": {
|
| 24 |
+
"type": "string",
|
| 25 |
+
"description": "What you want to say to other players (chat message). Use this for negotiation, threats, or table talk.",
|
| 26 |
+
"examples": [
|
| 27 |
+
"Anyone want to trade sheep for wood?",
|
| 28 |
+
"Red, can you give me 1 Brick for 2 Sheep?",
|
| 29 |
+
"I'm so behind, don't steal from me!"
|
| 30 |
+
]
|
| 31 |
+
},
|
| 32 |
+
"action": {
|
| 33 |
+
"type": "object",
|
| 34 |
+
"required": [
|
| 35 |
+
"type",
|
| 36 |
+
"parameters"
|
| 37 |
+
],
|
| 38 |
+
"properties": {
|
| 39 |
+
"type": {
|
| 40 |
+
"type": "string",
|
| 41 |
+
"description": "The action type (must match one from allowed_actions in constraints)",
|
| 42 |
+
"examples": [
|
| 43 |
+
"BUILD_SETTLEMENT",
|
| 44 |
+
"BUILD_ROAD",
|
| 45 |
+
"OFFER_TRADE",
|
| 46 |
+
"WAIT_FOR_RESPONSE",
|
| 47 |
+
"END_TURN"
|
| 48 |
+
]
|
| 49 |
+
},
|
| 50 |
+
"parameters": {
|
| 51 |
+
"type": "object",
|
| 52 |
+
"description": "Action-specific parameters (structure matches allowed_actions examples)"
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
},
|
| 57 |
+
"example": {
|
| 58 |
+
"internal_thinking": "I have 3 Sheep and 2 Wheat. I need Wood and Brick to build. I see Red asked for Sheep in the chat. My note says to trade with Red. I will offer him a deal verbally first to see if he accepts, before committing to a formal trade action. I won't pass turn yet.",
|
| 59 |
+
"note_to_self": "Waiting for Red's response. If he says yes, I will use OFFER_TRADE action next.",
|
| 60 |
+
"say_outloud": "Red, I have plenty of sheep. Can you give me 1 Wood and 1 Brick for 2 Sheep?",
|
| 61 |
+
"action": {
|
| 62 |
+
"type": "WAIT_FOR_RESPONSE",
|
| 63 |
+
"parameters": {}
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
},
|
| 67 |
+
"system_instruction": "You are an expert Settlers of Catan player. Respond in JSON format.",
|
| 68 |
+
"prompt": {
|
| 69 |
+
"meta_data": {
|
| 70 |
+
"agent_name": "a",
|
| 71 |
+
"my_color": "Red",
|
| 72 |
+
"role": "You are player 'a' (Red). Play strategically to win."
|
| 73 |
+
},
|
| 74 |
+
"task_context": {
|
| 75 |
+
"what_just_happened": "You rolled an 8. You received 2 wood.",
|
| 76 |
+
"instructions": "Choose your action from 'allowed_actions'."
|
| 77 |
+
},
|
| 78 |
+
"game_state": "\nFORMAT GUIDE:\n• H array: Index=HexID, Value=Resource+Number (W=Wood, B=Brick, S=Sheep, Wh=Wheat, O=Ore, D=Desert)\n• N array: Index=NodeID, Value=[[Neighbors], [HexIDs], Port?] where Port: ?3=Any(3:1), X2=Specific(2:1)\n• bld: [NodeID, Owner, Type] where Type: S=Settlement, C=City\n• rds: [[From, To], Owner]\n• Players res: {ResourceCode: Count}\n• Players dev: {\"h\": [Hidden], \"r\": [Revealed]} - Cards: K=Knight, M=Monopoly, Y=Year of Plenty, R=Road Building, V=Victory Point\n• Players stat: [\"LR\"=Longest Road, \"LA\"=Largest Army]\n\nGAME STATE:\n{\n \"H\": [\n \"\",\n \"W12\",\n \"S5\",\n \"W4\",\n \"S8\",\n \"B6\"\n ],\n \"N\": [\n [],\n [\n [\n 2,\n 5\n ],\n [\n 1,\n 2\n ],\n null\n ],\n [\n [\n 1,\n 3\n ],\n [\n 1,\n 3\n ],\n \"W2\"\n ]\n ],\n \"players\": {\n \"a\": {\n \"vp\": 2,\n \"res\": {\n \"W\": 3,\n \"B\": 1\n },\n \"dev\": {\n \"h\": [\n \"K\"\n ],\n \"r\": []\n },\n \"stat\": []\n },\n \"b\": {\n \"vp\": 1,\n \"res\": {\n \"S\": 2\n },\n \"dev\": {\n \"h\": [],\n \"r\": []\n },\n \"stat\": []\n }\n },\n \"bld\": [\n [\n 20,\n \"a\",\n \"S\"\n ],\n [\n 25,\n \"b\",\n \"S\"\n ]\n ],\n \"rds\": [\n [\n [\n 20,\n 21\n ],\n \"a\"\n ],\n [\n [\n 25,\n 26\n ],\n \"b\"\n ]\n ],\n \"meta\": {\n \"robber\": 10,\n \"phase\": \"MAIN_GAME\",\n \"curr\": \"a\",\n \"dice\": 8\n }\n}",
|
| 79 |
+
"social_context": {
|
| 80 |
+
"recent_chat": [
|
| 81 |
+
{
|
| 82 |
+
"sender": "b",
|
| 83 |
+
"content": "Anyone need sheep?"
|
| 84 |
+
}
|
| 85 |
+
]
|
| 86 |
+
},
|
| 87 |
+
"memory": {
|
| 88 |
+
"notes_for_myself": [
|
| 89 |
+
"b needs ore, I should trade",
|
| 90 |
+
"Focus on longest road"
|
| 91 |
+
]
|
| 92 |
+
},
|
| 93 |
+
"constraints": {
|
| 94 |
+
"usage_instructions": "Choose one action. Use exact parameter structure.",
|
| 95 |
+
"allowed_actions": [
|
| 96 |
+
{
|
| 97 |
+
"action": "build_road",
|
| 98 |
+
"description": "Build a road on an edge",
|
| 99 |
+
"example_parameters": {
|
| 100 |
+
"edge_id": 15
|
| 101 |
+
}
|
| 102 |
+
},
|
| 103 |
+
{
|
| 104 |
+
"action": "end_turn",
|
| 105 |
+
"description": "End your turn",
|
| 106 |
+
"example_parameters": {}
|
| 107 |
+
}
|
| 108 |
+
]
|
| 109 |
+
}
|
| 110 |
+
}
|
| 111 |
+
}
|
examples/ai_testing/my_games/test_prompt_output.json
DELETED
|
@@ -1,792 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"meta_data": {
|
| 3 |
-
"agent_name": "a",
|
| 4 |
-
"my_color": "Blue",
|
| 5 |
-
"role": "You are a strategic Catan player."
|
| 6 |
-
},
|
| 7 |
-
"task_context": {
|
| 8 |
-
"what_just_happened": "Game started. It's your turn to place your first settlement.",
|
| 9 |
-
"instructions": "Analyze the game state and select the optimal move from 'allowed_actions'. Only one action is currently available."
|
| 10 |
-
},
|
| 11 |
-
"game_state_legend": "OPTIMIZED STATE FORMAT GUIDE:\n \n1. LOOKUP TABLES:\n • \"H\" (Hexes): Array where Index = HexID. Value = Resource+Num.\n Example: H[1]=\"W12\" → Hex 1 is Wood with number 12\n • \"N\" (Nodes): Array where Index = NodeID.\n Format: [[Neighbors], [HexIDs], Port?]\n To find yield: Check N[node_id], get HexIDs, look up in H array\n\n2. RESOURCE CODES:\n W=Wood, B=Brick, S=Sheep, Wh=Wheat, O=Ore, D=Desert\n Ports: ?3=Any(3:1), X2=Specific(2:1) where X is resource\n\n3. GAME STATE:\n \"bld\": [NodeID, Owner, Type] where Type: S=Settlement, C=City\n \"rds\": [[From, To], Owner]\n\n4. PLAYERS:\n \"res\": {ResourceCode: Count}\n \"dev\": {\"h\": [HiddenCards], \"r\": [RevealedCards]}\n \"stat\": [\"LR\"=Longest Road, \"LA\"=Largest Army]\n\n5. META:\n \"robber\": HexID where robber is located (blocks that hex)\n \"phase\": Current game phase\n \"curr\": Current player's turn\n",
|
| 12 |
-
"game_state": {
|
| 13 |
-
"my_private_info": {
|
| 14 |
-
"resources": {},
|
| 15 |
-
"development_cards": {
|
| 16 |
-
"hidden": [],
|
| 17 |
-
"revealed": []
|
| 18 |
-
},
|
| 19 |
-
"victory_points": 1,
|
| 20 |
-
"has_longest_road": false,
|
| 21 |
-
"has_largest_army": false
|
| 22 |
-
},
|
| 23 |
-
"board_state": {
|
| 24 |
-
"H": [
|
| 25 |
-
"",
|
| 26 |
-
"W12",
|
| 27 |
-
"S5",
|
| 28 |
-
"W4",
|
| 29 |
-
"S8",
|
| 30 |
-
"B6",
|
| 31 |
-
"W3",
|
| 32 |
-
"Wh8",
|
| 33 |
-
"B10",
|
| 34 |
-
"W11",
|
| 35 |
-
"D",
|
| 36 |
-
"O3",
|
| 37 |
-
"S4",
|
| 38 |
-
"B10",
|
| 39 |
-
"Wh9",
|
| 40 |
-
"Wh6",
|
| 41 |
-
"S11",
|
| 42 |
-
"O5",
|
| 43 |
-
"Wh9",
|
| 44 |
-
"O2"
|
| 45 |
-
],
|
| 46 |
-
"N": [
|
| 47 |
-
null,
|
| 48 |
-
[
|
| 49 |
-
[
|
| 50 |
-
2,
|
| 51 |
-
9
|
| 52 |
-
],
|
| 53 |
-
[
|
| 54 |
-
1
|
| 55 |
-
]
|
| 56 |
-
],
|
| 57 |
-
[
|
| 58 |
-
[
|
| 59 |
-
1,
|
| 60 |
-
3
|
| 61 |
-
],
|
| 62 |
-
[
|
| 63 |
-
1
|
| 64 |
-
],
|
| 65 |
-
"Wh2"
|
| 66 |
-
],
|
| 67 |
-
[
|
| 68 |
-
[
|
| 69 |
-
2,
|
| 70 |
-
4,
|
| 71 |
-
11
|
| 72 |
-
],
|
| 73 |
-
[
|
| 74 |
-
2,
|
| 75 |
-
1
|
| 76 |
-
],
|
| 77 |
-
"Wh2"
|
| 78 |
-
],
|
| 79 |
-
[
|
| 80 |
-
[
|
| 81 |
-
3,
|
| 82 |
-
5
|
| 83 |
-
],
|
| 84 |
-
[
|
| 85 |
-
2
|
| 86 |
-
]
|
| 87 |
-
],
|
| 88 |
-
[
|
| 89 |
-
[
|
| 90 |
-
4,
|
| 91 |
-
6,
|
| 92 |
-
13
|
| 93 |
-
],
|
| 94 |
-
[
|
| 95 |
-
3,
|
| 96 |
-
2
|
| 97 |
-
]
|
| 98 |
-
],
|
| 99 |
-
[
|
| 100 |
-
[
|
| 101 |
-
5,
|
| 102 |
-
7
|
| 103 |
-
],
|
| 104 |
-
[
|
| 105 |
-
3
|
| 106 |
-
],
|
| 107 |
-
"B2"
|
| 108 |
-
],
|
| 109 |
-
[
|
| 110 |
-
[
|
| 111 |
-
6,
|
| 112 |
-
15
|
| 113 |
-
],
|
| 114 |
-
[
|
| 115 |
-
3
|
| 116 |
-
],
|
| 117 |
-
"B2"
|
| 118 |
-
],
|
| 119 |
-
[
|
| 120 |
-
[
|
| 121 |
-
9,
|
| 122 |
-
18
|
| 123 |
-
],
|
| 124 |
-
[
|
| 125 |
-
4
|
| 126 |
-
],
|
| 127 |
-
"?3"
|
| 128 |
-
],
|
| 129 |
-
[
|
| 130 |
-
[
|
| 131 |
-
8,
|
| 132 |
-
10,
|
| 133 |
-
1
|
| 134 |
-
],
|
| 135 |
-
[
|
| 136 |
-
4,
|
| 137 |
-
1
|
| 138 |
-
],
|
| 139 |
-
"?3"
|
| 140 |
-
],
|
| 141 |
-
[
|
| 142 |
-
[
|
| 143 |
-
9,
|
| 144 |
-
11,
|
| 145 |
-
20
|
| 146 |
-
],
|
| 147 |
-
[
|
| 148 |
-
5,
|
| 149 |
-
4,
|
| 150 |
-
1
|
| 151 |
-
]
|
| 152 |
-
],
|
| 153 |
-
[
|
| 154 |
-
[
|
| 155 |
-
10,
|
| 156 |
-
12,
|
| 157 |
-
3
|
| 158 |
-
],
|
| 159 |
-
[
|
| 160 |
-
5,
|
| 161 |
-
2,
|
| 162 |
-
1
|
| 163 |
-
]
|
| 164 |
-
],
|
| 165 |
-
[
|
| 166 |
-
[
|
| 167 |
-
11,
|
| 168 |
-
13,
|
| 169 |
-
22
|
| 170 |
-
],
|
| 171 |
-
[
|
| 172 |
-
6,
|
| 173 |
-
5,
|
| 174 |
-
2
|
| 175 |
-
]
|
| 176 |
-
],
|
| 177 |
-
[
|
| 178 |
-
[
|
| 179 |
-
12,
|
| 180 |
-
14,
|
| 181 |
-
5
|
| 182 |
-
],
|
| 183 |
-
[
|
| 184 |
-
6,
|
| 185 |
-
3,
|
| 186 |
-
2
|
| 187 |
-
]
|
| 188 |
-
],
|
| 189 |
-
[
|
| 190 |
-
[
|
| 191 |
-
13,
|
| 192 |
-
15,
|
| 193 |
-
24
|
| 194 |
-
],
|
| 195 |
-
[
|
| 196 |
-
7,
|
| 197 |
-
6,
|
| 198 |
-
3
|
| 199 |
-
]
|
| 200 |
-
],
|
| 201 |
-
[
|
| 202 |
-
[
|
| 203 |
-
14,
|
| 204 |
-
16,
|
| 205 |
-
7
|
| 206 |
-
],
|
| 207 |
-
[
|
| 208 |
-
7,
|
| 209 |
-
3
|
| 210 |
-
]
|
| 211 |
-
],
|
| 212 |
-
[
|
| 213 |
-
[
|
| 214 |
-
15,
|
| 215 |
-
26
|
| 216 |
-
],
|
| 217 |
-
[
|
| 218 |
-
7
|
| 219 |
-
],
|
| 220 |
-
"O2"
|
| 221 |
-
],
|
| 222 |
-
[
|
| 223 |
-
[
|
| 224 |
-
18,
|
| 225 |
-
28
|
| 226 |
-
],
|
| 227 |
-
[
|
| 228 |
-
8
|
| 229 |
-
],
|
| 230 |
-
"S2"
|
| 231 |
-
],
|
| 232 |
-
[
|
| 233 |
-
[
|
| 234 |
-
17,
|
| 235 |
-
19,
|
| 236 |
-
8
|
| 237 |
-
],
|
| 238 |
-
[
|
| 239 |
-
8,
|
| 240 |
-
4
|
| 241 |
-
]
|
| 242 |
-
],
|
| 243 |
-
[
|
| 244 |
-
[
|
| 245 |
-
18,
|
| 246 |
-
20,
|
| 247 |
-
30
|
| 248 |
-
],
|
| 249 |
-
[
|
| 250 |
-
9,
|
| 251 |
-
8,
|
| 252 |
-
4
|
| 253 |
-
]
|
| 254 |
-
],
|
| 255 |
-
[
|
| 256 |
-
[
|
| 257 |
-
19,
|
| 258 |
-
21,
|
| 259 |
-
10
|
| 260 |
-
],
|
| 261 |
-
[
|
| 262 |
-
9,
|
| 263 |
-
5,
|
| 264 |
-
4
|
| 265 |
-
]
|
| 266 |
-
],
|
| 267 |
-
[
|
| 268 |
-
[
|
| 269 |
-
20,
|
| 270 |
-
22,
|
| 271 |
-
32
|
| 272 |
-
],
|
| 273 |
-
[
|
| 274 |
-
10,
|
| 275 |
-
9,
|
| 276 |
-
5
|
| 277 |
-
]
|
| 278 |
-
],
|
| 279 |
-
[
|
| 280 |
-
[
|
| 281 |
-
21,
|
| 282 |
-
23,
|
| 283 |
-
12
|
| 284 |
-
],
|
| 285 |
-
[
|
| 286 |
-
10,
|
| 287 |
-
6,
|
| 288 |
-
5
|
| 289 |
-
]
|
| 290 |
-
],
|
| 291 |
-
[
|
| 292 |
-
[
|
| 293 |
-
22,
|
| 294 |
-
24,
|
| 295 |
-
34
|
| 296 |
-
],
|
| 297 |
-
[
|
| 298 |
-
11,
|
| 299 |
-
10,
|
| 300 |
-
6
|
| 301 |
-
]
|
| 302 |
-
],
|
| 303 |
-
[
|
| 304 |
-
[
|
| 305 |
-
23,
|
| 306 |
-
25,
|
| 307 |
-
14
|
| 308 |
-
],
|
| 309 |
-
[
|
| 310 |
-
11,
|
| 311 |
-
7,
|
| 312 |
-
6
|
| 313 |
-
]
|
| 314 |
-
],
|
| 315 |
-
[
|
| 316 |
-
[
|
| 317 |
-
24,
|
| 318 |
-
26,
|
| 319 |
-
36
|
| 320 |
-
],
|
| 321 |
-
[
|
| 322 |
-
12,
|
| 323 |
-
11,
|
| 324 |
-
7
|
| 325 |
-
]
|
| 326 |
-
],
|
| 327 |
-
[
|
| 328 |
-
[
|
| 329 |
-
25,
|
| 330 |
-
27,
|
| 331 |
-
16
|
| 332 |
-
],
|
| 333 |
-
[
|
| 334 |
-
12,
|
| 335 |
-
7
|
| 336 |
-
],
|
| 337 |
-
"O2"
|
| 338 |
-
],
|
| 339 |
-
[
|
| 340 |
-
[
|
| 341 |
-
26,
|
| 342 |
-
38
|
| 343 |
-
],
|
| 344 |
-
[
|
| 345 |
-
12
|
| 346 |
-
]
|
| 347 |
-
],
|
| 348 |
-
[
|
| 349 |
-
[
|
| 350 |
-
29,
|
| 351 |
-
17
|
| 352 |
-
],
|
| 353 |
-
[
|
| 354 |
-
8
|
| 355 |
-
],
|
| 356 |
-
"S2"
|
| 357 |
-
],
|
| 358 |
-
[
|
| 359 |
-
[
|
| 360 |
-
28,
|
| 361 |
-
30,
|
| 362 |
-
39
|
| 363 |
-
],
|
| 364 |
-
[
|
| 365 |
-
13,
|
| 366 |
-
8
|
| 367 |
-
]
|
| 368 |
-
],
|
| 369 |
-
[
|
| 370 |
-
[
|
| 371 |
-
29,
|
| 372 |
-
31,
|
| 373 |
-
19
|
| 374 |
-
],
|
| 375 |
-
[
|
| 376 |
-
13,
|
| 377 |
-
9,
|
| 378 |
-
8
|
| 379 |
-
]
|
| 380 |
-
],
|
| 381 |
-
[
|
| 382 |
-
[
|
| 383 |
-
30,
|
| 384 |
-
32,
|
| 385 |
-
41
|
| 386 |
-
],
|
| 387 |
-
[
|
| 388 |
-
14,
|
| 389 |
-
13,
|
| 390 |
-
9
|
| 391 |
-
]
|
| 392 |
-
],
|
| 393 |
-
[
|
| 394 |
-
[
|
| 395 |
-
31,
|
| 396 |
-
33,
|
| 397 |
-
21
|
| 398 |
-
],
|
| 399 |
-
[
|
| 400 |
-
14,
|
| 401 |
-
10,
|
| 402 |
-
9
|
| 403 |
-
]
|
| 404 |
-
],
|
| 405 |
-
[
|
| 406 |
-
[
|
| 407 |
-
32,
|
| 408 |
-
34,
|
| 409 |
-
43
|
| 410 |
-
],
|
| 411 |
-
[
|
| 412 |
-
15,
|
| 413 |
-
14,
|
| 414 |
-
10
|
| 415 |
-
]
|
| 416 |
-
],
|
| 417 |
-
[
|
| 418 |
-
[
|
| 419 |
-
33,
|
| 420 |
-
35,
|
| 421 |
-
23
|
| 422 |
-
],
|
| 423 |
-
[
|
| 424 |
-
15,
|
| 425 |
-
11,
|
| 426 |
-
10
|
| 427 |
-
]
|
| 428 |
-
],
|
| 429 |
-
[
|
| 430 |
-
[
|
| 431 |
-
34,
|
| 432 |
-
36,
|
| 433 |
-
45
|
| 434 |
-
],
|
| 435 |
-
[
|
| 436 |
-
16,
|
| 437 |
-
15,
|
| 438 |
-
11
|
| 439 |
-
]
|
| 440 |
-
],
|
| 441 |
-
[
|
| 442 |
-
[
|
| 443 |
-
35,
|
| 444 |
-
37,
|
| 445 |
-
25
|
| 446 |
-
],
|
| 447 |
-
[
|
| 448 |
-
16,
|
| 449 |
-
12,
|
| 450 |
-
11
|
| 451 |
-
]
|
| 452 |
-
],
|
| 453 |
-
[
|
| 454 |
-
[
|
| 455 |
-
36,
|
| 456 |
-
38,
|
| 457 |
-
47
|
| 458 |
-
],
|
| 459 |
-
[
|
| 460 |
-
16,
|
| 461 |
-
12
|
| 462 |
-
],
|
| 463 |
-
"?3"
|
| 464 |
-
],
|
| 465 |
-
[
|
| 466 |
-
[
|
| 467 |
-
37,
|
| 468 |
-
27
|
| 469 |
-
],
|
| 470 |
-
[
|
| 471 |
-
12
|
| 472 |
-
],
|
| 473 |
-
"?3"
|
| 474 |
-
],
|
| 475 |
-
[
|
| 476 |
-
[
|
| 477 |
-
40,
|
| 478 |
-
29
|
| 479 |
-
],
|
| 480 |
-
[
|
| 481 |
-
13
|
| 482 |
-
]
|
| 483 |
-
],
|
| 484 |
-
[
|
| 485 |
-
[
|
| 486 |
-
39,
|
| 487 |
-
41,
|
| 488 |
-
48
|
| 489 |
-
],
|
| 490 |
-
[
|
| 491 |
-
17,
|
| 492 |
-
13
|
| 493 |
-
],
|
| 494 |
-
"W2"
|
| 495 |
-
],
|
| 496 |
-
[
|
| 497 |
-
[
|
| 498 |
-
40,
|
| 499 |
-
42,
|
| 500 |
-
31
|
| 501 |
-
],
|
| 502 |
-
[
|
| 503 |
-
17,
|
| 504 |
-
14,
|
| 505 |
-
13
|
| 506 |
-
]
|
| 507 |
-
],
|
| 508 |
-
[
|
| 509 |
-
[
|
| 510 |
-
41,
|
| 511 |
-
43,
|
| 512 |
-
50
|
| 513 |
-
],
|
| 514 |
-
[
|
| 515 |
-
18,
|
| 516 |
-
17,
|
| 517 |
-
14
|
| 518 |
-
]
|
| 519 |
-
],
|
| 520 |
-
[
|
| 521 |
-
[
|
| 522 |
-
42,
|
| 523 |
-
44,
|
| 524 |
-
33
|
| 525 |
-
],
|
| 526 |
-
[
|
| 527 |
-
18,
|
| 528 |
-
15,
|
| 529 |
-
14
|
| 530 |
-
]
|
| 531 |
-
],
|
| 532 |
-
[
|
| 533 |
-
[
|
| 534 |
-
43,
|
| 535 |
-
45,
|
| 536 |
-
52
|
| 537 |
-
],
|
| 538 |
-
[
|
| 539 |
-
19,
|
| 540 |
-
18,
|
| 541 |
-
15
|
| 542 |
-
]
|
| 543 |
-
],
|
| 544 |
-
[
|
| 545 |
-
[
|
| 546 |
-
44,
|
| 547 |
-
46,
|
| 548 |
-
35
|
| 549 |
-
],
|
| 550 |
-
[
|
| 551 |
-
19,
|
| 552 |
-
16,
|
| 553 |
-
15
|
| 554 |
-
]
|
| 555 |
-
],
|
| 556 |
-
[
|
| 557 |
-
[
|
| 558 |
-
45,
|
| 559 |
-
47,
|
| 560 |
-
54
|
| 561 |
-
],
|
| 562 |
-
[
|
| 563 |
-
19,
|
| 564 |
-
16
|
| 565 |
-
]
|
| 566 |
-
],
|
| 567 |
-
[
|
| 568 |
-
[
|
| 569 |
-
46,
|
| 570 |
-
37
|
| 571 |
-
],
|
| 572 |
-
[
|
| 573 |
-
16
|
| 574 |
-
]
|
| 575 |
-
],
|
| 576 |
-
[
|
| 577 |
-
[
|
| 578 |
-
49,
|
| 579 |
-
40
|
| 580 |
-
],
|
| 581 |
-
[
|
| 582 |
-
17
|
| 583 |
-
],
|
| 584 |
-
"W2"
|
| 585 |
-
],
|
| 586 |
-
[
|
| 587 |
-
[
|
| 588 |
-
48,
|
| 589 |
-
50
|
| 590 |
-
],
|
| 591 |
-
[
|
| 592 |
-
17
|
| 593 |
-
]
|
| 594 |
-
],
|
| 595 |
-
[
|
| 596 |
-
[
|
| 597 |
-
49,
|
| 598 |
-
51,
|
| 599 |
-
42
|
| 600 |
-
],
|
| 601 |
-
[
|
| 602 |
-
18,
|
| 603 |
-
17
|
| 604 |
-
],
|
| 605 |
-
"?3"
|
| 606 |
-
],
|
| 607 |
-
[
|
| 608 |
-
[
|
| 609 |
-
50,
|
| 610 |
-
52
|
| 611 |
-
],
|
| 612 |
-
[
|
| 613 |
-
18
|
| 614 |
-
],
|
| 615 |
-
"?3"
|
| 616 |
-
],
|
| 617 |
-
[
|
| 618 |
-
[
|
| 619 |
-
51,
|
| 620 |
-
53,
|
| 621 |
-
44
|
| 622 |
-
],
|
| 623 |
-
[
|
| 624 |
-
19,
|
| 625 |
-
18
|
| 626 |
-
]
|
| 627 |
-
],
|
| 628 |
-
[
|
| 629 |
-
[
|
| 630 |
-
52,
|
| 631 |
-
54
|
| 632 |
-
],
|
| 633 |
-
[
|
| 634 |
-
19
|
| 635 |
-
],
|
| 636 |
-
"?3"
|
| 637 |
-
],
|
| 638 |
-
[
|
| 639 |
-
[
|
| 640 |
-
53,
|
| 641 |
-
46
|
| 642 |
-
],
|
| 643 |
-
[
|
| 644 |
-
19
|
| 645 |
-
],
|
| 646 |
-
"?3"
|
| 647 |
-
]
|
| 648 |
-
],
|
| 649 |
-
"buildings": [
|
| 650 |
-
{
|
| 651 |
-
"node": 20,
|
| 652 |
-
"owner": "me",
|
| 653 |
-
"type": "settlement"
|
| 654 |
-
}
|
| 655 |
-
],
|
| 656 |
-
"roads": [
|
| 657 |
-
{
|
| 658 |
-
"from": 20,
|
| 659 |
-
"to": 10,
|
| 660 |
-
"owner": "me"
|
| 661 |
-
}
|
| 662 |
-
],
|
| 663 |
-
"robber_hex": 10,
|
| 664 |
-
"current_phase": "SETUP_FIRST_ROUND",
|
| 665 |
-
"dice_result": null
|
| 666 |
-
},
|
| 667 |
-
"other_players": [
|
| 668 |
-
{
|
| 669 |
-
"name": "b",
|
| 670 |
-
"victory_points": 0,
|
| 671 |
-
"resource_count": 0,
|
| 672 |
-
"development_card_count": 0,
|
| 673 |
-
"knights_played": 0,
|
| 674 |
-
"has_longest_road": false,
|
| 675 |
-
"has_largest_army": false
|
| 676 |
-
},
|
| 677 |
-
{
|
| 678 |
-
"name": "c",
|
| 679 |
-
"victory_points": 0,
|
| 680 |
-
"resource_count": 0,
|
| 681 |
-
"development_card_count": 0,
|
| 682 |
-
"knights_played": 0,
|
| 683 |
-
"has_longest_road": false,
|
| 684 |
-
"has_largest_army": false
|
| 685 |
-
}
|
| 686 |
-
],
|
| 687 |
-
"strategic_context": {
|
| 688 |
-
"hex_analysis": [
|
| 689 |
-
{
|
| 690 |
-
"hex_id": 1,
|
| 691 |
-
"resource": "W",
|
| 692 |
-
"number": 12,
|
| 693 |
-
"probability": "2.8%"
|
| 694 |
-
},
|
| 695 |
-
{
|
| 696 |
-
"hex_id": 2,
|
| 697 |
-
"resource": "S",
|
| 698 |
-
"number": 5,
|
| 699 |
-
"probability": "11.1%"
|
| 700 |
-
},
|
| 701 |
-
{
|
| 702 |
-
"hex_id": 3,
|
| 703 |
-
"resource": "W",
|
| 704 |
-
"number": 4,
|
| 705 |
-
"probability": "8.3%"
|
| 706 |
-
},
|
| 707 |
-
{
|
| 708 |
-
"hex_id": 4,
|
| 709 |
-
"resource": "S",
|
| 710 |
-
"number": 8,
|
| 711 |
-
"probability": "13.9%"
|
| 712 |
-
},
|
| 713 |
-
{
|
| 714 |
-
"hex_id": 5,
|
| 715 |
-
"resource": "B",
|
| 716 |
-
"number": 6,
|
| 717 |
-
"probability": "13.9%"
|
| 718 |
-
},
|
| 719 |
-
{
|
| 720 |
-
"hex_id": 6,
|
| 721 |
-
"resource": "W",
|
| 722 |
-
"number": 3,
|
| 723 |
-
"probability": "5.6%"
|
| 724 |
-
},
|
| 725 |
-
{
|
| 726 |
-
"hex_id": 8,
|
| 727 |
-
"resource": "B",
|
| 728 |
-
"number": 10,
|
| 729 |
-
"probability": "8.3%"
|
| 730 |
-
},
|
| 731 |
-
{
|
| 732 |
-
"hex_id": 9,
|
| 733 |
-
"resource": "W",
|
| 734 |
-
"number": 11,
|
| 735 |
-
"probability": "5.6%"
|
| 736 |
-
},
|
| 737 |
-
{
|
| 738 |
-
"hex_id": 11,
|
| 739 |
-
"resource": "O",
|
| 740 |
-
"number": 3,
|
| 741 |
-
"probability": "5.6%"
|
| 742 |
-
},
|
| 743 |
-
{
|
| 744 |
-
"hex_id": 12,
|
| 745 |
-
"resource": "S",
|
| 746 |
-
"number": 4,
|
| 747 |
-
"probability": "8.3%"
|
| 748 |
-
},
|
| 749 |
-
{
|
| 750 |
-
"hex_id": 13,
|
| 751 |
-
"resource": "B",
|
| 752 |
-
"number": 10,
|
| 753 |
-
"probability": "8.3%"
|
| 754 |
-
},
|
| 755 |
-
{
|
| 756 |
-
"hex_id": 16,
|
| 757 |
-
"resource": "S",
|
| 758 |
-
"number": 11,
|
| 759 |
-
"probability": "5.6%"
|
| 760 |
-
},
|
| 761 |
-
{
|
| 762 |
-
"hex_id": 17,
|
| 763 |
-
"resource": "O",
|
| 764 |
-
"number": 5,
|
| 765 |
-
"probability": "11.1%"
|
| 766 |
-
},
|
| 767 |
-
{
|
| 768 |
-
"hex_id": 19,
|
| 769 |
-
"resource": "O",
|
| 770 |
-
"number": 2,
|
| 771 |
-
"probability": "2.8%"
|
| 772 |
-
}
|
| 773 |
-
],
|
| 774 |
-
"leading_player": "a",
|
| 775 |
-
"current_player": "b",
|
| 776 |
-
"game_phase": "SETUP_FIRST_ROUND",
|
| 777 |
-
"robber_location": 10
|
| 778 |
-
}
|
| 779 |
-
},
|
| 780 |
-
"constraints": {
|
| 781 |
-
"usage_instructions": "Choose one action type from the list below. Populate the 'parameters' field in your response strictly according to the 'example_parameters' structure provided.",
|
| 782 |
-
"allowed_actions": [
|
| 783 |
-
{
|
| 784 |
-
"action": "place_settlement",
|
| 785 |
-
"description": "Place your starting settlement",
|
| 786 |
-
"example_parameters": {
|
| 787 |
-
"node_id": 20
|
| 788 |
-
}
|
| 789 |
-
}
|
| 790 |
-
]
|
| 791 |
-
}
|
| 792 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
examples/ai_testing/play_and_capture.py
CHANGED
|
@@ -417,6 +417,26 @@ def main():
|
|
| 417 |
try:
|
| 418 |
# Start game
|
| 419 |
game = RealGame()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 420 |
game.run()
|
| 421 |
|
| 422 |
except KeyboardInterrupt:
|
|
|
|
| 417 |
try:
|
| 418 |
# Start game
|
| 419 |
game = RealGame()
|
| 420 |
+
|
| 421 |
+
# 🎯 CRITICAL: Install turn start callback BEFORE running game
|
| 422 |
+
# This ensures state is saved at the BEGINNING of each turn
|
| 423 |
+
def on_turn_start(game_state):
|
| 424 |
+
"""Called at the start of each turn, before showing to user."""
|
| 425 |
+
# Convert GameState object to dict
|
| 426 |
+
from pycatan.visualizations.web_visualization import WebVisualization
|
| 427 |
+
web_viz = WebVisualization()
|
| 428 |
+
web_viz.update_full_state(game_state)
|
| 429 |
+
|
| 430 |
+
if hasattr(web_viz, 'current_game_state') and web_viz.current_game_state:
|
| 431 |
+
state_copy = json.loads(json.dumps(web_viz.current_game_state))
|
| 432 |
+
captured_states.append(state_copy)
|
| 433 |
+
print(f"[🎯 Turn Start - Captured state #{len(captured_states)}]", flush=True)
|
| 434 |
+
save_current_state(state_copy)
|
| 435 |
+
|
| 436 |
+
# Install the callback
|
| 437 |
+
if hasattr(game, 'game_manager'):
|
| 438 |
+
game.game_manager._on_turn_start_callback = on_turn_start
|
| 439 |
+
|
| 440 |
game.run()
|
| 441 |
|
| 442 |
except KeyboardInterrupt:
|
examples/ai_testing/play_with_prompts.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Play Catan with Auto-Generated Prompts
|
| 3 |
+
---------------------------------------
|
| 4 |
+
This version generates AI prompts for each player at the START of every turn.
|
| 5 |
+
|
| 6 |
+
During the game, you'll see:
|
| 7 |
+
- Game proceeds normally
|
| 8 |
+
- At each turn start, prompts are automatically generated for all players
|
| 9 |
+
- Prompts are saved to: examples/ai_testing/my_games/prompts/
|
| 10 |
+
|
| 11 |
+
This lets you see exactly what each AI agent would receive as input.
|
| 12 |
+
"""
|
| 13 |
+
|
| 14 |
+
import sys
|
| 15 |
+
from pathlib import Path
|
| 16 |
+
import subprocess
|
| 17 |
+
import time
|
| 18 |
+
import threading
|
| 19 |
+
|
| 20 |
+
# Add parent directory to path
|
| 21 |
+
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
| 22 |
+
|
| 23 |
+
# Import the original capture script's functionality
|
| 24 |
+
from examples.ai_testing import play_and_capture
|
| 25 |
+
|
| 26 |
+
# Import prompt generator
|
| 27 |
+
from examples.ai_testing.generate_prompts_from_state import main as generate_prompts
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def prompt_generator_thread():
|
| 31 |
+
"""
|
| 32 |
+
Background thread that watches for state changes and generates prompts.
|
| 33 |
+
"""
|
| 34 |
+
state_file = Path('examples/ai_testing/my_games/current_state_optimized.txt')
|
| 35 |
+
last_modified = 0
|
| 36 |
+
|
| 37 |
+
print("\n[🤖 Prompt Generator Active - will generate prompts on state changes]")
|
| 38 |
+
|
| 39 |
+
while True:
|
| 40 |
+
try:
|
| 41 |
+
if state_file.exists():
|
| 42 |
+
current_modified = state_file.stat().st_mtime
|
| 43 |
+
|
| 44 |
+
# If file was modified, generate prompts
|
| 45 |
+
if current_modified > last_modified:
|
| 46 |
+
last_modified = current_modified
|
| 47 |
+
|
| 48 |
+
# Wait a tiny bit to ensure file is fully written
|
| 49 |
+
time.sleep(0.1)
|
| 50 |
+
|
| 51 |
+
print("\n" + "🔄 " + "-"*70)
|
| 52 |
+
print("🔄 State changed - generating AI prompts for all players...")
|
| 53 |
+
print("🔄 " + "-"*70)
|
| 54 |
+
|
| 55 |
+
try:
|
| 56 |
+
# Generate prompts
|
| 57 |
+
generate_prompts()
|
| 58 |
+
print("🔄 " + "-"*70)
|
| 59 |
+
print("✅ Prompts generated! Check examples/ai_testing/my_games/prompts/")
|
| 60 |
+
print("🔄 " + "-"*70 + "\n")
|
| 61 |
+
except Exception as e:
|
| 62 |
+
print(f"⚠️ Error generating prompts: {e}\n")
|
| 63 |
+
|
| 64 |
+
# Check every 0.5 seconds
|
| 65 |
+
time.sleep(0.5)
|
| 66 |
+
|
| 67 |
+
except KeyboardInterrupt:
|
| 68 |
+
break
|
| 69 |
+
except Exception as e:
|
| 70 |
+
# Ignore errors silently
|
| 71 |
+
time.sleep(1)
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def main():
|
| 75 |
+
"""Main entry point."""
|
| 76 |
+
print("="*80)
|
| 77 |
+
print("🎮 CATAN WITH AUTO-GENERATED AI PROMPTS")
|
| 78 |
+
print("="*80)
|
| 79 |
+
print("\n📝 This version automatically generates AI prompts for each player!")
|
| 80 |
+
print("📁 Prompts saved to: examples/ai_testing/my_games/prompts/")
|
| 81 |
+
print("⏱️ Prompts generated at the START of each turn")
|
| 82 |
+
print("\n" + "="*80 + "\n")
|
| 83 |
+
|
| 84 |
+
# Start prompt generator thread
|
| 85 |
+
generator = threading.Thread(target=prompt_generator_thread, daemon=True)
|
| 86 |
+
generator.start()
|
| 87 |
+
|
| 88 |
+
# Give thread time to start
|
| 89 |
+
time.sleep(0.5)
|
| 90 |
+
|
| 91 |
+
# Run the game (this will block)
|
| 92 |
+
try:
|
| 93 |
+
play_and_capture.main()
|
| 94 |
+
except KeyboardInterrupt:
|
| 95 |
+
print("\n\n✅ Game stopped")
|
| 96 |
+
except EOFError:
|
| 97 |
+
print("\n\n✅ Game completed")
|
| 98 |
+
except Exception as e:
|
| 99 |
+
print(f"\n\n❌ Error: {e}")
|
| 100 |
+
import traceback
|
| 101 |
+
traceback.print_exc()
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
if __name__ == '__main__':
|
| 105 |
+
main()
|
examples/ai_testing/test_json_format.py
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Test JSON Prompt Format
|
| 3 |
+
-----------------------
|
| 4 |
+
Quick test to verify the new JSON format matches promt_format.text structure.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import sys
|
| 8 |
+
import json
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
|
| 11 |
+
# Add parent directory to path
|
| 12 |
+
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
| 13 |
+
|
| 14 |
+
from pycatan.ai.prompt_templates import PromptBuilder, get_response_schema
|
| 15 |
+
from pycatan.ai.config import AIConfig
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def test_prompt_structure():
|
| 19 |
+
"""Test that generated prompts match expected structure."""
|
| 20 |
+
print("\n" + "="*80)
|
| 21 |
+
print("🧪 TESTING JSON PROMPT FORMAT")
|
| 22 |
+
print("="*80 + "\n")
|
| 23 |
+
|
| 24 |
+
# Create sample optimized game state
|
| 25 |
+
sample_state = {
|
| 26 |
+
"H": ["", "W12", "S5", "W4", "S8", "B6"],
|
| 27 |
+
"N": [
|
| 28 |
+
[], # 0 - empty
|
| 29 |
+
[[2, 5], [1, 2], None], # Node 1
|
| 30 |
+
[[1, 3], [1, 3], "W2"], # Node 2 with wood port
|
| 31 |
+
],
|
| 32 |
+
"players": {
|
| 33 |
+
"a": {
|
| 34 |
+
"vp": 2,
|
| 35 |
+
"res": {"W": 3, "B": 1},
|
| 36 |
+
"dev": {"h": ["K"], "r": []},
|
| 37 |
+
"stat": []
|
| 38 |
+
},
|
| 39 |
+
"b": {
|
| 40 |
+
"vp": 1,
|
| 41 |
+
"res": {"S": 2},
|
| 42 |
+
"dev": {"h": [], "r": []},
|
| 43 |
+
"stat": []
|
| 44 |
+
}
|
| 45 |
+
},
|
| 46 |
+
"bld": [
|
| 47 |
+
[20, "a", "S"],
|
| 48 |
+
[25, "b", "S"]
|
| 49 |
+
],
|
| 50 |
+
"rds": [
|
| 51 |
+
[[20, 21], "a"],
|
| 52 |
+
[[25, 26], "b"]
|
| 53 |
+
],
|
| 54 |
+
"meta": {
|
| 55 |
+
"robber": 10,
|
| 56 |
+
"phase": "MAIN_GAME",
|
| 57 |
+
"curr": "a",
|
| 58 |
+
"dice": 8
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
# Build prompt
|
| 63 |
+
builder = PromptBuilder()
|
| 64 |
+
|
| 65 |
+
prompt = builder.build_prompt(
|
| 66 |
+
meta_data={
|
| 67 |
+
"agent_name": "a",
|
| 68 |
+
"my_color": "Red",
|
| 69 |
+
"role": "You are player 'a' (Red). Play strategically to win."
|
| 70 |
+
},
|
| 71 |
+
task_context={
|
| 72 |
+
"what_just_happened": "You rolled an 8. You received 2 wood.",
|
| 73 |
+
"instructions": "Choose your action from 'allowed_actions'."
|
| 74 |
+
},
|
| 75 |
+
game_state=sample_state,
|
| 76 |
+
social_context={
|
| 77 |
+
"recent_chat": [
|
| 78 |
+
{"sender": "b", "content": "Anyone need sheep?"}
|
| 79 |
+
]
|
| 80 |
+
},
|
| 81 |
+
memory=[
|
| 82 |
+
"b needs ore, I should trade",
|
| 83 |
+
"Focus on longest road"
|
| 84 |
+
],
|
| 85 |
+
constraints={
|
| 86 |
+
"usage_instructions": "Choose one action. Use exact parameter structure.",
|
| 87 |
+
"allowed_actions": [
|
| 88 |
+
{
|
| 89 |
+
"action": "build_road",
|
| 90 |
+
"description": "Build a road on an edge",
|
| 91 |
+
"example_parameters": {"edge_id": 15}
|
| 92 |
+
},
|
| 93 |
+
{
|
| 94 |
+
"action": "end_turn",
|
| 95 |
+
"description": "End your turn",
|
| 96 |
+
"example_parameters": {}
|
| 97 |
+
}
|
| 98 |
+
]
|
| 99 |
+
}
|
| 100 |
+
)
|
| 101 |
+
|
| 102 |
+
# Verify structure matches promt_format.text
|
| 103 |
+
print("✅ Testing prompt structure...\n")
|
| 104 |
+
|
| 105 |
+
required_sections = ["meta_data", "task_context", "game_state",
|
| 106 |
+
"social_context", "memory", "constraints"]
|
| 107 |
+
|
| 108 |
+
for section in required_sections:
|
| 109 |
+
if section in prompt:
|
| 110 |
+
print(f" ✓ {section}")
|
| 111 |
+
else:
|
| 112 |
+
print(f" ❌ Missing: {section}")
|
| 113 |
+
|
| 114 |
+
print("\n📋 Meta Data:")
|
| 115 |
+
print(f" • agent_name: {prompt['meta_data'].get('agent_name')}")
|
| 116 |
+
print(f" • my_color: {prompt['meta_data'].get('my_color')}")
|
| 117 |
+
print(f" • role: {prompt['meta_data'].get('role')[:50]}...")
|
| 118 |
+
|
| 119 |
+
print("\n📋 Task Context:")
|
| 120 |
+
print(f" • what_just_happened: {prompt['task_context'].get('what_just_happened')}")
|
| 121 |
+
|
| 122 |
+
print("\n📋 Game State:")
|
| 123 |
+
game_state = prompt.get('game_state', '')
|
| 124 |
+
if isinstance(game_state, str):
|
| 125 |
+
lines = game_state.split('\n')
|
| 126 |
+
print(f" • Type: String with embedded JSON")
|
| 127 |
+
print(f" • Lines: {len(lines)}")
|
| 128 |
+
print(f" • Has legend: {'FORMAT GUIDE' in game_state}")
|
| 129 |
+
print(f" • Has H array: {'\"H\":' in game_state}")
|
| 130 |
+
print(f" • First 100 chars: {game_state[:100]}...")
|
| 131 |
+
|
| 132 |
+
print("\n📋 Social Context:")
|
| 133 |
+
print(f" • recent_chat: {len(prompt['social_context'].get('recent_chat', []))} messages")
|
| 134 |
+
|
| 135 |
+
print("\n📋 Memory:")
|
| 136 |
+
print(f" • notes_for_myself: {len(prompt['memory'].get('notes_for_myself', []))} notes")
|
| 137 |
+
|
| 138 |
+
print("\n📋 Constraints:")
|
| 139 |
+
print(f" • allowed_actions: {len(prompt['constraints'].get('allowed_actions', []))} actions")
|
| 140 |
+
|
| 141 |
+
# Test response schema
|
| 142 |
+
print("\n" + "="*80)
|
| 143 |
+
print("📝 Response Schema:")
|
| 144 |
+
print("="*80)
|
| 145 |
+
schema = get_response_schema()
|
| 146 |
+
print(json.dumps(schema, indent=2))
|
| 147 |
+
|
| 148 |
+
# Create full LLM request
|
| 149 |
+
print("\n" + "="*80)
|
| 150 |
+
print("📤 Complete LLM Request Structure:")
|
| 151 |
+
print("="*80)
|
| 152 |
+
|
| 153 |
+
llm_request = {
|
| 154 |
+
"response_schema": schema,
|
| 155 |
+
"system_instruction": "You are an expert Settlers of Catan player. Respond in JSON format.",
|
| 156 |
+
"prompt": prompt
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
# Save to file
|
| 160 |
+
output_file = Path('examples/ai_testing/my_games/test_prompt_format.json')
|
| 161 |
+
output_file.parent.mkdir(exist_ok=True, parents=True)
|
| 162 |
+
|
| 163 |
+
with open(output_file, 'w', encoding='utf-8') as f:
|
| 164 |
+
json.dump(llm_request, f, indent=2, ensure_ascii=False)
|
| 165 |
+
|
| 166 |
+
print(f"\n✅ Saved complete request to: {output_file}")
|
| 167 |
+
print(f"📏 File size: {output_file.stat().st_size:,} bytes")
|
| 168 |
+
|
| 169 |
+
# Estimate tokens (rough)
|
| 170 |
+
json_str = json.dumps(llm_request, ensure_ascii=False)
|
| 171 |
+
estimated_tokens = len(json_str) // 4
|
| 172 |
+
print(f"📊 Estimated tokens: ~{estimated_tokens:,}")
|
| 173 |
+
|
| 174 |
+
print("\n" + "="*80)
|
| 175 |
+
print("✅ ALL TESTS PASSED!")
|
| 176 |
+
print("="*80)
|
| 177 |
+
print("\n💡 The prompt format matches promt_format.text structure:")
|
| 178 |
+
print(" • meta_data ✓")
|
| 179 |
+
print(" • task_context ✓")
|
| 180 |
+
print(" • game_state (with legend) ✓")
|
| 181 |
+
print(" • social_context ✓")
|
| 182 |
+
print(" • memory ✓")
|
| 183 |
+
print(" • constraints ✓")
|
| 184 |
+
print("\n💡 Complete LLM request includes:")
|
| 185 |
+
print(" • response_schema (tells LLM how to respond)")
|
| 186 |
+
print(" • system_instruction")
|
| 187 |
+
print(" • prompt (the actual game state)")
|
| 188 |
+
print("\n" + "="*80 + "\n")
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
if __name__ == '__main__':
|
| 192 |
+
test_prompt_structure()
|
promt_format.text
CHANGED
|
@@ -11,12 +11,9 @@
|
|
| 11 |
"instructions": "Analyze the game state and select the optimal move from 'allowed_actions'. You may use the provided tools to gather more data (e.g., calculate probabilities), but limit yourself to a maximum of 3 tool executions per decision. If you wish to negotiate or wait for other players, select the 'WAIT_FOR_RESPONSE' action.",
|
| 12 |
},
|
| 13 |
// קונטקסט על הSTATE של העולם מותאם לנקודת המבט של השחקן
|
| 14 |
-
"game_state":
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
"development_cards": [],
|
| 18 |
-
"victory_points": 2
|
| 19 |
-
},....
|
| 20 |
},
|
| 21 |
|
| 22 |
"social_context": {
|
|
|
|
| 11 |
"instructions": "Analyze the game state and select the optimal move from 'allowed_actions'. You may use the provided tools to gather more data (e.g., calculate probabilities), but limit yourself to a maximum of 3 tool executions per decision. If you wish to negotiate or wait for other players, select the 'WAIT_FOR_RESPONSE' action.",
|
| 12 |
},
|
| 13 |
// קונטקסט על הSTATE של העולם מותאם לנקודת המבט של השחקן
|
| 14 |
+
"game_state": " ENTER HERE THE OPTIMEZED TEXT + JSON
|
| 15 |
+
|
| 16 |
+
"
|
|
|
|
|
|
|
|
|
|
| 17 |
},
|
| 18 |
|
| 19 |
"social_context": {
|
pycatan/ai/prompt_manager.py
CHANGED
|
@@ -273,14 +273,19 @@ class PromptManager:
|
|
| 273 |
"Analyze the game state and select the optimal move from 'allowed_actions'. "
|
| 274 |
)
|
| 275 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 276 |
if available_actions:
|
| 277 |
num_actions = len(available_actions)
|
| 278 |
if num_actions == 1:
|
| 279 |
return base_instructions + "Only one action is currently available."
|
| 280 |
else:
|
| 281 |
-
return base_instructions + f"You have {num_actions} possible actions
|
| 282 |
|
| 283 |
-
return base_instructions +
|
| 284 |
|
| 285 |
def clear_cache(self):
|
| 286 |
"""Clear the filter cache. Useful when starting a new game."""
|
|
|
|
| 273 |
"Analyze the game state and select the optimal move from 'allowed_actions'. "
|
| 274 |
)
|
| 275 |
|
| 276 |
+
wait_info = (
|
| 277 |
+
"Note: 'wait_for_response' is always available if you want to chat, "
|
| 278 |
+
"negotiate trades, or observe before taking action."
|
| 279 |
+
)
|
| 280 |
+
|
| 281 |
if available_actions:
|
| 282 |
num_actions = len(available_actions)
|
| 283 |
if num_actions == 1:
|
| 284 |
return base_instructions + "Only one action is currently available."
|
| 285 |
else:
|
| 286 |
+
return base_instructions + f"You have {num_actions} possible actions. " + wait_info
|
| 287 |
|
| 288 |
+
return base_instructions + wait_info
|
| 289 |
|
| 290 |
def clear_cache(self):
|
| 291 |
"""Clear the filter cache. Useful when starting a new game."""
|
pycatan/ai/prompt_templates.py
CHANGED
|
@@ -91,7 +91,7 @@ class PromptBuilder:
|
|
| 91 |
"""
|
| 92 |
prompt = {}
|
| 93 |
|
| 94 |
-
# Build each section
|
| 95 |
if self.template.include_meta_data:
|
| 96 |
prompt["meta_data"] = self._build_meta_data(meta_data, custom_instructions)
|
| 97 |
|
|
@@ -99,9 +99,8 @@ class PromptBuilder:
|
|
| 99 |
prompt["task_context"] = self._build_task_context(task_context)
|
| 100 |
|
| 101 |
if self.template.include_game_state:
|
| 102 |
-
#
|
| 103 |
-
prompt["
|
| 104 |
-
prompt["game_state"] = game_state
|
| 105 |
|
| 106 |
if self.template.include_social_context and social_context:
|
| 107 |
prompt["social_context"] = self._build_social_context(social_context)
|
|
@@ -114,40 +113,40 @@ class PromptBuilder:
|
|
| 114 |
|
| 115 |
return prompt
|
| 116 |
|
| 117 |
-
def
|
| 118 |
"""
|
| 119 |
-
Build
|
| 120 |
|
|
|
|
|
|
|
|
|
|
| 121 |
Returns:
|
| 122 |
-
|
| 123 |
"""
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
1. LOOKUP TABLES:
|
| 127 |
• "H" (Hexes): Array where Index = HexID. Value = Resource+Num.
|
| 128 |
-
Example: H[1]="W12"
|
| 129 |
• "N" (Nodes): Array where Index = NodeID.
|
| 130 |
-
Format: [[Neighbors], [HexIDs], Port?]
|
| 131 |
-
To find yield
|
| 132 |
|
| 133 |
-
2.
|
| 134 |
-
|
| 135 |
-
Ports: ?3=Any(3:1), X2=Specific(2:1) where X is resource
|
| 136 |
|
| 137 |
-
3.
|
| 138 |
-
"bld": [NodeID, Owner, Type] where Type: S=Settlement, C=City
|
| 139 |
-
"rds": [[From, To], Owner]
|
| 140 |
|
| 141 |
-
4. PLAYERS:
|
| 142 |
-
|
| 143 |
-
"dev": {"h": [HiddenCards], "r": [RevealedCards]}
|
| 144 |
-
"stat": ["LR"=Longest Road, "LA"=Largest Army]
|
| 145 |
|
| 146 |
-
5.
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
"curr": Current player's turn
|
| 150 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 151 |
|
| 152 |
def _build_meta_data(
|
| 153 |
self,
|
|
@@ -226,24 +225,36 @@ class PromptBuilder:
|
|
| 226 |
Build memory section with agent's notes.
|
| 227 |
|
| 228 |
Args:
|
| 229 |
-
memory: Agent's observations and plans
|
| 230 |
|
| 231 |
Returns:
|
| 232 |
Formatted memory
|
| 233 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 234 |
return {
|
| 235 |
-
"notes_for_myself":
|
| 236 |
-
"strategic_observations": memory.get("observations", []),
|
| 237 |
-
"player_tracking": memory.get("player_tracking", {})
|
| 238 |
}
|
| 239 |
|
| 240 |
def _build_constraints(self, constraints: Dict[str, Any]) -> Dict[str, Any]:
|
| 241 |
"""
|
| 242 |
Build constraints section with available actions.
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 246 |
|
|
|
|
|
|
|
| 247 |
Returns:
|
| 248 |
Formatted constraints
|
| 249 |
"""
|
|
@@ -413,6 +424,55 @@ class ActionTemplates:
|
|
| 413 |
return affordable
|
| 414 |
|
| 415 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 416 |
def create_default_prompt_builder() -> PromptBuilder:
|
| 417 |
"""
|
| 418 |
Create a prompt builder with default settings.
|
|
|
|
| 91 |
"""
|
| 92 |
prompt = {}
|
| 93 |
|
| 94 |
+
# Build each section according to promt_format.text structure
|
| 95 |
if self.template.include_meta_data:
|
| 96 |
prompt["meta_data"] = self._build_meta_data(meta_data, custom_instructions)
|
| 97 |
|
|
|
|
| 99 |
prompt["task_context"] = self._build_task_context(task_context)
|
| 100 |
|
| 101 |
if self.template.include_game_state:
|
| 102 |
+
# Include optimized game state with legend embedded
|
| 103 |
+
prompt["game_state"] = self._build_game_state_section(game_state)
|
|
|
|
| 104 |
|
| 105 |
if self.template.include_social_context and social_context:
|
| 106 |
prompt["social_context"] = self._build_social_context(social_context)
|
|
|
|
| 113 |
|
| 114 |
return prompt
|
| 115 |
|
| 116 |
+
def _build_game_state_section(self, game_state: Dict[str, Any]) -> str:
|
| 117 |
"""
|
| 118 |
+
Build game state section with compact legend and single-line JSON.
|
| 119 |
|
| 120 |
+
Args:
|
| 121 |
+
game_state: Optimized game state
|
| 122 |
+
|
| 123 |
Returns:
|
| 124 |
+
Complete game state as formatted string with legend
|
| 125 |
"""
|
| 126 |
+
legend = """
|
| 127 |
+
1. LOOKUP TABLES:
|
|
|
|
| 128 |
• "H" (Hexes): Array where Index = HexID. Value = Resource+Num.
|
| 129 |
+
Example: H[1]="W12" -> Hex 1 is Wood 12.
|
| 130 |
• "N" (Nodes): Array where Index = NodeID.
|
| 131 |
+
Format: [ [Neighbors], [HexIDs], Port? ]
|
| 132 |
+
Logic: To find yield of Node 10, check N[10]. Get HexIDs (e.g. [1,5]). Look up H[1] and H[5].
|
| 133 |
|
| 134 |
+
2. CODES: W=Wood, B=Brick, S=Sheep, Wh=Wheat, O=Ore, D=Desert.
|
| 135 |
+
?3=Any 3:1 port, X2=Specific Resource 2:1 port.
|
|
|
|
| 136 |
|
| 137 |
+
3. STATE: "bld"=[NodeID, Owner, Type], "rds"=[[From,To], Owner].
|
|
|
|
|
|
|
| 138 |
|
| 139 |
+
4. PLAYERS: "res"={Resource:Count}, "dev"={"h":[Hidden Cards], "r":[Revealed] (K=Knight)},
|
| 140 |
+
"stat"=["LR" (Longest Road), "LA" (Largest Army)].
|
|
|
|
|
|
|
| 141 |
|
| 142 |
+
5. ROBBER: Located at HexID specified in "meta.robber". H[id] is blocked.
|
| 143 |
+
|
| 144 |
+
JSON:
|
|
|
|
| 145 |
"""
|
| 146 |
+
# Convert game state to compact single-line JSON
|
| 147 |
+
import json
|
| 148 |
+
compact_json = json.dumps(game_state, ensure_ascii=False, separators=(',', ':'))
|
| 149 |
+
return legend + compact_json
|
| 150 |
|
| 151 |
def _build_meta_data(
|
| 152 |
self,
|
|
|
|
| 225 |
Build memory section with agent's notes.
|
| 226 |
|
| 227 |
Args:
|
| 228 |
+
memory: Agent's observations and plans (can be list or dict)
|
| 229 |
|
| 230 |
Returns:
|
| 231 |
Formatted memory
|
| 232 |
"""
|
| 233 |
+
# Support both dict format and list format
|
| 234 |
+
if isinstance(memory, list):
|
| 235 |
+
notes = memory
|
| 236 |
+
elif isinstance(memory, dict):
|
| 237 |
+
notes = memory.get("notes", [])
|
| 238 |
+
else:
|
| 239 |
+
notes = []
|
| 240 |
+
|
| 241 |
return {
|
| 242 |
+
"notes_for_myself": notes
|
|
|
|
|
|
|
| 243 |
}
|
| 244 |
|
| 245 |
def _build_constraints(self, constraints: Dict[str, Any]) -> Dict[str, Any]:
|
| 246 |
"""
|
| 247 |
Build constraints section with available actions.
|
| 248 |
+
# Support both dict format and list format
|
| 249 |
+
if isinstance(memory, dict):
|
| 250 |
+
notes = memory.get("notes", [])
|
| 251 |
+
elif isinstance(memory, list):
|
| 252 |
+
notes = memory
|
| 253 |
+
else:
|
| 254 |
+
notes = []
|
| 255 |
|
| 256 |
+
return {
|
| 257 |
+
"notes_for_myself": notes
|
| 258 |
Returns:
|
| 259 |
Formatted constraints
|
| 260 |
"""
|
|
|
|
| 424 |
return affordable
|
| 425 |
|
| 426 |
|
| 427 |
+
def get_response_schema() -> Dict[str, Any]:
|
| 428 |
+
"""
|
| 429 |
+
Get the expected response schema for LLM output.
|
| 430 |
+
Based on example_answer.md structure.
|
| 431 |
+
OpenAPI-compliant (no 'examples' inside properties).
|
| 432 |
+
|
| 433 |
+
Returns:
|
| 434 |
+
JSON schema defining expected response format
|
| 435 |
+
"""
|
| 436 |
+
return {
|
| 437 |
+
"type": "object",
|
| 438 |
+
"required": ["internal_thinking", "action"],
|
| 439 |
+
"properties": {
|
| 440 |
+
"internal_thinking": {
|
| 441 |
+
"type": "string",
|
| 442 |
+
"description": "Your private reasoning about the situation, strategy, and decision-making process. This is for you only.",
|
| 443 |
+
"minLength": 50
|
| 444 |
+
},
|
| 445 |
+
"note_to_self": {
|
| 446 |
+
"type": "string",
|
| 447 |
+
"description": "A note to remember for next turn. What are you waiting for? What's your plan?"
|
| 448 |
+
},
|
| 449 |
+
"say_outloud": {
|
| 450 |
+
"type": "string",
|
| 451 |
+
"description": "What you want to say to other players (chat message). Use this for negotiation, threats, or table talk."
|
| 452 |
+
},
|
| 453 |
+
"action": {
|
| 454 |
+
"type": "object",
|
| 455 |
+
"required": ["type", "parameters"],
|
| 456 |
+
"properties": {
|
| 457 |
+
"type": {
|
| 458 |
+
"type": "string",
|
| 459 |
+
"description": "The action type (must match one from allowed_actions in constraints)"
|
| 460 |
+
},
|
| 461 |
+
"parameters": {
|
| 462 |
+
"type": "object",
|
| 463 |
+
"description": "Action-specific parameters. If no parameters are needed, provide an empty object.",
|
| 464 |
+
"properties": {
|
| 465 |
+
"target": {"type": "string", "description": "The target of the action (if applicable)"},
|
| 466 |
+
"amount": {"type": "number", "description": "The amount (if applicable)"},
|
| 467 |
+
"location": {"type": "string", "description": "The location (if applicable)"}
|
| 468 |
+
}
|
| 469 |
+
}
|
| 470 |
+
}
|
| 471 |
+
}
|
| 472 |
+
}
|
| 473 |
+
}
|
| 474 |
+
|
| 475 |
+
|
| 476 |
def create_default_prompt_builder() -> PromptBuilder:
|
| 477 |
"""
|
| 478 |
Create a prompt builder with default settings.
|
pycatan/ai/state_filter.py
CHANGED
|
@@ -48,29 +48,20 @@ class StateFilter:
|
|
| 48 |
|
| 49 |
def filter_game_state(self, raw_state: Dict[str, Any]) -> Dict[str, Any]:
|
| 50 |
"""
|
| 51 |
-
Main filtering method -
|
|
|
|
|
|
|
|
|
|
| 52 |
|
| 53 |
Args:
|
| 54 |
-
raw_state:
|
| 55 |
|
| 56 |
Returns:
|
| 57 |
-
|
| 58 |
"""
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
filtered["my_private_info"] = self._extract_my_info(raw_state)
|
| 63 |
-
|
| 64 |
-
# 2. Get visible board state
|
| 65 |
-
filtered["board_state"] = self._filter_board_state(raw_state)
|
| 66 |
-
|
| 67 |
-
# 3. Get other players' public information
|
| 68 |
-
filtered["other_players"] = self._filter_other_players(raw_state)
|
| 69 |
-
|
| 70 |
-
# 4. Add computed/helpful context
|
| 71 |
-
filtered["strategic_context"] = self._add_strategic_context(raw_state)
|
| 72 |
-
|
| 73 |
-
return filtered
|
| 74 |
|
| 75 |
def _extract_my_info(self, raw_state: Dict[str, Any]) -> Dict[str, Any]:
|
| 76 |
"""
|
|
|
|
| 48 |
|
| 49 |
def filter_game_state(self, raw_state: Dict[str, Any]) -> Dict[str, Any]:
|
| 50 |
"""
|
| 51 |
+
Main filtering method - returns optimized compact state AS-IS.
|
| 52 |
+
|
| 53 |
+
The state is already in compact format (H, N, players, bld, rds, meta).
|
| 54 |
+
This filter just returns it directly - the compactness IS the optimization.
|
| 55 |
|
| 56 |
Args:
|
| 57 |
+
raw_state: Optimized game state (already compact)
|
| 58 |
|
| 59 |
Returns:
|
| 60 |
+
The same compact state (H, N arrays, etc.)
|
| 61 |
"""
|
| 62 |
+
# The optimized state is already perfect for LLM consumption
|
| 63 |
+
# Just return it as-is
|
| 64 |
+
return raw_state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
|
| 66 |
def _extract_my_info(self, raw_state: Dict[str, Any]) -> Dict[str, Any]:
|
| 67 |
"""
|
pycatan/management/game_manager.py
CHANGED
|
@@ -1735,8 +1735,15 @@ class GameManager:
|
|
| 1735 |
player_name = self.users[player_id].name if hasattr(self.users[player_id], 'name') else f"Player {player_id + 1}"
|
| 1736 |
self.visualization_manager.display_turn_start(player_name, self._current_game_state.turn_number)
|
| 1737 |
|
| 1738 |
-
#
|
|
|
|
| 1739 |
current_state = self.get_full_state()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1740 |
self.visualization_manager.display_game_state(current_state)
|
| 1741 |
|
| 1742 |
def _handle_game_end(self) -> None:
|
|
|
|
| 1735 |
player_name = self.users[player_id].name if hasattr(self.users[player_id], 'name') else f"Player {player_id + 1}"
|
| 1736 |
self.visualization_manager.display_turn_start(player_name, self._current_game_state.turn_number)
|
| 1737 |
|
| 1738 |
+
# 🎯 CRITICAL: Get state BEFORE displaying to user
|
| 1739 |
+
# This ensures AI prompts are generated with correct turn state
|
| 1740 |
current_state = self.get_full_state()
|
| 1741 |
+
|
| 1742 |
+
# Trigger state capture for AI prompt generation (if hook is installed)
|
| 1743 |
+
if hasattr(self, '_on_turn_start_callback'):
|
| 1744 |
+
self._on_turn_start_callback(current_state)
|
| 1745 |
+
|
| 1746 |
+
# Display full game state at start of turn
|
| 1747 |
self.visualization_manager.display_game_state(current_state)
|
| 1748 |
|
| 1749 |
def _handle_game_end(self) -> None:
|
temp_viz_console.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
# -*- coding: utf-8 -*-
|
| 3 |
+
import sys
|
| 4 |
+
import time
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
log_file = r"c:\GIT_new\PyCatan_AI\logs\game_viz.log"
|
| 8 |
+
|
| 9 |
+
print("PyCatan - Game Visualization Console")
|
| 10 |
+
print("=" * 50)
|
| 11 |
+
print("This window shows real-time game state updates.")
|
| 12 |
+
print("Keep this window open while playing!")
|
| 13 |
+
print("=" * 50)
|
| 14 |
+
print(f"Reading from: {log_file}")
|
| 15 |
+
|
| 16 |
+
# Wait for file to exist
|
| 17 |
+
while not os.path.exists(log_file):
|
| 18 |
+
time.sleep(0.1)
|
| 19 |
+
|
| 20 |
+
# Tail the file
|
| 21 |
+
with open(log_file, 'r', encoding='utf-8') as f:
|
| 22 |
+
# Go to the end of file
|
| 23 |
+
# f.seek(0, 2)
|
| 24 |
+
# Actually start from beginning since we just created it
|
| 25 |
+
|
| 26 |
+
while True:
|
| 27 |
+
line = f.readline()
|
| 28 |
+
if line:
|
| 29 |
+
print(line, end='')
|
| 30 |
+
else:
|
| 31 |
+
time.sleep(0.1)
|