EZTIME2025 commited on
Commit
fb4d798
·
1 Parent(s): 6016237

promt and scheme eng

Browse files
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
- "my_private_info": {
16
- "resources": {"wood": 0, "brick": 0, "sheep": 3, "wheat": 1, "ore": 0},
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 to choose from."
282
 
283
- return base_instructions + "Consider all strategic implications before deciding."
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
- # Add legend before game state for optimized format
103
- prompt["game_state_legend"] = self._build_legend()
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 _build_legend(self) -> str:
118
  """
119
- Build legend for optimized game state format.
120
 
 
 
 
121
  Returns:
122
- Legend explaining the compact format
123
  """
124
- return """OPTIMIZED STATE FORMAT GUIDE:
125
-
126
- 1. LOOKUP TABLES:
127
  • "H" (Hexes): Array where Index = HexID. Value = Resource+Num.
128
- Example: H[1]="W12" Hex 1 is Wood with number 12
129
  • "N" (Nodes): Array where Index = NodeID.
130
- Format: [[Neighbors], [HexIDs], Port?]
131
- To find yield: Check N[node_id], get HexIDs, look up in H array
132
 
133
- 2. RESOURCE CODES:
134
- W=Wood, B=Brick, S=Sheep, Wh=Wheat, O=Ore, D=Desert
135
- Ports: ?3=Any(3:1), X2=Specific(2:1) where X is resource
136
 
137
- 3. GAME STATE:
138
- "bld": [NodeID, Owner, Type] where Type: S=Settlement, C=City
139
- "rds": [[From, To], Owner]
140
 
141
- 4. PLAYERS:
142
- "res": {ResourceCode: Count}
143
- "dev": {"h": [HiddenCards], "r": [RevealedCards]}
144
- "stat": ["LR"=Longest Road, "LA"=Largest Army]
145
 
146
- 5. META:
147
- "robber": HexID where robber is located (blocks that hex)
148
- "phase": Current game phase
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": memory.get("notes", []),
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
- Args:
245
- constraints: Available actions and rules
 
 
 
 
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 - converts raw game state to agent view.
 
 
 
52
 
53
  Args:
54
- raw_state: Complete game state from the game engine
55
 
56
  Returns:
57
- Filtered game state from agent's perspective
58
  """
59
- filtered = {}
60
-
61
- # 1. Extract and format my private information
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
- # Display full game state at start of turn (CRITICAL FOR AI!)
 
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)