faaizashiq commited on
Commit
fe224e3
·
verified ·
1 Parent(s): 7c8b1f0

Update backend/agents/puzzle_agent.py

Browse files
Files changed (1) hide show
  1. backend/agents/puzzle_agent.py +56 -32
backend/agents/puzzle_agent.py CHANGED
@@ -31,7 +31,16 @@ class PuzzleAgent:
31
  }
32
 
33
  self.high_rated_levels = []
34
-
 
 
 
 
 
 
 
 
 
35
  def _generate_maze_grid(self, size: int) -> list:
36
  """Generates a perfect, guaranteed solvable maze using Recursive Backtracking."""
37
  # Force size to be odd for perfect wall alignment
@@ -82,10 +91,22 @@ class PuzzleAgent:
82
  if len(self.high_rated_levels) > 50: self.high_rated_levels.pop(0)
83
  self.high_rated_levels.append(level_data)
84
 
85
- def _get_system_prompt(self, difficulty: str, specific_topic: str, generated_grids: list) -> str:
 
 
 
 
 
 
 
 
 
 
86
  base_prompt = f"""
87
  You are the Lead Game Designer for 'CodeCracker', an educational coding game for ages 10-14.
88
- Your task is to generate a UNIQUE STORY ARC of EXACTLY 5 interconnected game levels in JSON format.
 
 
89
 
90
  CURRENT SETTINGS:
91
  - Mode: maze
@@ -100,43 +121,45 @@ class PuzzleAgent:
100
  Grid 4: {json.dumps(generated_grids[3])}
101
  Grid 5: {json.dumps(generated_grids[4])}
102
 
 
103
  - 0 = Path
104
  - 1 = Wall
105
- - 2 = Start
106
- - 3 = Goal
107
- - 4 = Hazard / Killing Point (MUST be avoided or jumped over!)
 
 
108
 
109
- You MUST assign Grid 1 to Level 1's grid_layout, Grid 2 to Level 2's grid_layout, and so on.
110
- You must write engaging stories, hints, and goals explaining the hazards (the 4s).
 
 
111
 
112
  DYNAMIC PROCEDURAL UI INSTRUCTION (THEME PALETTE):
113
- You must act as a UI Designer. Based on the {specific_topic} story, generate a modern Glassmorphism hex color palette.
114
- It MUST be returned in the root JSON.
115
-
116
- OUTPUT FORMAT: RAW JSON ONLY (No Markdown).
117
 
118
  REQUIRED JSON STRUCTURE:
119
  {{
120
  "story_arc_title": "Epic Title",
121
  "theme_palette": {{
122
- "background_gradient": ["#0F2027", "#203A43"], // 2 to 3 colors
123
- "wall_color": "#00FFCC",
124
- "path_color": "#121212",
125
- "hazard_glow": "#FF0055"
126
  }},
127
  "levels": [
128
  {{
129
  "type": "maze",
130
- "level_id": "UUID_STRING",
131
- "title": "Level 1: The Breach",
132
- "story": "Engaging scenario explaining the objective and hazards.",
133
- "concept_tutorial": "EDUCATIONAL: Explain the CS concept (Sequencing, Loops) in 2 simple sentences.",
134
- "goal_description": "What to do.",
135
- "grid_layout": [[...]], // MUST USE THE EXACT GRID PROVIDED FOR THIS LEVEL (e.g. Grid 1 for Level 1)
136
  "allowed_blocks": ["move_forward", "turn_left", "turn_right", "jump"],
137
  "optimal_steps": 10,
138
- "hint_1": "General hint",
139
- "hint_2": "Specific hint about jumping the hazard (if any)"
140
  }}
141
  ]
142
  }}
@@ -144,18 +167,19 @@ class PuzzleAgent:
144
  return base_prompt
145
 
146
  def generate_level(self, difficulty: str, specific_topic: Optional[str] = None) -> Dict[str, Any]:
147
- if not specific_topic:
148
- category = random.choice(list(self.topics.keys()))
149
- specific_topic = random.choice(self.topics[category])
 
 
 
150
 
151
  # Generate 5 progressively harder mathematical grids
152
- base_size = 5
153
- if difficulty == "Intermediate": base_size = 7
154
- elif difficulty == "Expert": base_size = 9
155
 
156
  perfect_grids = []
157
  for i in range(5):
158
- size = base_size + (2 if i >= 3 else 0) # Level 4 and 5 get larger
159
  perfect_grids.append(self._generate_maze_grid(size))
160
 
161
  cache_key = f"maze_{difficulty}_{specific_topic}"
@@ -164,7 +188,7 @@ class PuzzleAgent:
164
  if time.time() - entry['timestamp'] < self.cache_duration:
165
  return entry['data']
166
 
167
- prompt = self._get_system_prompt(difficulty, specific_topic, perfect_grids)
168
 
169
  try:
170
  if not self.model: raise Exception("No API Key")
 
31
  }
32
 
33
  self.high_rated_levels = []
34
+
35
+ # Load the 500 Logic Scenarios
36
+ self.scenarios_path = os.path.join(os.getcwd(), "data", "maze_scenarios_500.json")
37
+ self.scenarios = []
38
+ try:
39
+ with open(self.scenarios_path, 'r') as f:
40
+ data = json.load(f)
41
+ self.scenarios = data.get("scenarios", [])
42
+ except Exception as e:
43
+ print(f"WARNING: Could not load maze_scenarios_500.json: {e}")
44
  def _generate_maze_grid(self, size: int) -> list:
45
  """Generates a perfect, guaranteed solvable maze using Recursive Backtracking."""
46
  # Force size to be odd for perfect wall alignment
 
91
  if len(self.high_rated_levels) > 50: self.high_rated_levels.pop(0)
92
  self.high_rated_levels.append(level_data)
93
 
94
+ def _get_system_prompt(self, difficulty: str, specific_topic: str, generated_grids: list, scenario_context: Dict = None) -> str:
95
+ mission_context = ""
96
+ if scenario_context:
97
+ mission_context = f"""
98
+ MISSION SCENARIO:
99
+ - Goal: {scenario_context.get('title')}
100
+ - Objective: {scenario_context.get('story')}
101
+ - Logic Steps: {', '.join(scenario_context.get('required_steps', []))}
102
+ - Objective: You MUST incorporate these logic steps into the 5-level story arc.
103
+ """
104
+
105
  base_prompt = f"""
106
  You are the Lead Game Designer for 'CodeCracker', an educational coding game for ages 10-14.
107
+ Your task is to generate a UNIQUE MISSION ARC of EXACTLY 5 interconnected game levels in JSON format.
108
+
109
+ {mission_context}
110
 
111
  CURRENT SETTINGS:
112
  - Mode: maze
 
121
  Grid 4: {json.dumps(generated_grids[3])}
122
  Grid 5: {json.dumps(generated_grids[4])}
123
 
124
+ TILE ID SCHEMA:
125
  - 0 = Path
126
  - 1 = Wall
127
+ - 2 = Start (Captain Cody)
128
+ - 3 = Goal / Final Mission Point
129
+ - 4 = Hazard (☠️ Skull) - Must be avoided/jumped!
130
+ - 5 = Mission Item (Locker/Key/Terminal) - Must be visited!
131
+ - 8 = NPC / Expert (Manager/Scientist) - Must be visited!
132
 
133
+ LOGIC RULES:
134
+ 1. Level 1 must introduce the mission.
135
+ 2. Progressively place Tile IDs 5 and 8 in the grids for later levels to represent mission steps.
136
+ 3. You MUST assign Grid 1 to Level 1, Grid 2 to Level 2, etc.
137
 
138
  DYNAMIC PROCEDURAL UI INSTRUCTION (THEME PALETTE):
139
+ You must act as a UI Designer. Generate a modern Glassmorphism hex color palette based on the {specific_topic} and {scenario_context.get('theme') if scenario_context else 'Space'} story.
 
 
 
140
 
141
  REQUIRED JSON STRUCTURE:
142
  {{
143
  "story_arc_title": "Epic Title",
144
  "theme_palette": {{
145
+ "background_gradient": ["#HEX", "#HEX"],
146
+ "wall_color": "#HEX",
147
+ "path_color": "#HEX",
148
+ "hazard_glow": "#HEX"
149
  }},
150
  "levels": [
151
  {{
152
  "type": "maze",
153
+ "level_id": "UUID",
154
+ "title": "Level Name",
155
+ "story": "Mission-driven story based on the scenario steps.",
156
+ "concept_tutorial": "Explain the logic concept.",
157
+ "goal_description": "Objective (e.g. 'Go to the Manager (8) first, then the Locker (5)')",
158
+ "grid_layout": [[...]], // MUST USE PROVIDED GRIDS
159
  "allowed_blocks": ["move_forward", "turn_left", "turn_right", "jump"],
160
  "optimal_steps": 10,
161
+ "hint_1": "Logic hint",
162
+ "hint_2": "Hazard hint"
163
  }}
164
  ]
165
  }}
 
167
  return base_prompt
168
 
169
  def generate_level(self, difficulty: str, specific_topic: Optional[str] = None) -> Dict[str, Any]:
170
+ # Pick a random Logic Scenario context from the JSON
171
+ scenario = {}
172
+ if self.scenarios:
173
+ filtered = [s for s in self.scenarios if s.get('difficulty', '').lower() == difficulty.lower()]
174
+ scenario = random.choice(filtered if filtered else self.scenarios)
175
+ specific_topic = scenario.get('theme', specific_topic)
176
 
177
  # Generate 5 progressively harder mathematical grids
178
+ base_size = scenario.get('grid_size', 5) if scenario else 5
 
 
179
 
180
  perfect_grids = []
181
  for i in range(5):
182
+ size = base_size + (2 if i >= 3 else 0)
183
  perfect_grids.append(self._generate_maze_grid(size))
184
 
185
  cache_key = f"maze_{difficulty}_{specific_topic}"
 
188
  if time.time() - entry['timestamp'] < self.cache_duration:
189
  return entry['data']
190
 
191
+ prompt = self._get_system_prompt(difficulty, specific_topic, perfect_grids, scenario)
192
 
193
  try:
194
  if not self.model: raise Exception("No API Key")