Spaces:
Runtime error
Runtime error
| """ | |
| ChessEcon Backend — Position Complexity Analyzer | |
| Decides when a position is complex enough to warrant calling Claude. | |
| Claude is only called when ALL three gates pass: | |
| 1. Position complexity >= threshold | |
| 2. Agent wallet >= minimum | |
| 3. Agent's own policy requests coaching | |
| """ | |
| from __future__ import annotations | |
| import os | |
| from shared.models import ComplexityAnalysis, PositionComplexity | |
| THRESHOLD_COMPLEX = float(os.getenv("COMPLEXITY_THRESHOLD_COMPLEX", "0.45")) | |
| THRESHOLD_CRITICAL = float(os.getenv("COMPLEXITY_THRESHOLD_CRITICAL", "0.70")) | |
| class ComplexityAnalyzer: | |
| def analyze(self, features: dict) -> ComplexityAnalysis: | |
| """ | |
| Compute a 0–1 complexity score from raw board features. | |
| Higher = more complex = more likely Claude is useful. | |
| """ | |
| score = 0.0 | |
| factors: dict = {} | |
| # Factor 1: Number of legal moves (high = complex position) | |
| num_moves = features.get("num_legal_moves", 20) | |
| move_score = min(num_moves / 60.0, 1.0) | |
| factors["mobility"] = round(move_score, 3) | |
| score += move_score * 0.30 | |
| # Factor 2: Check pressure | |
| check_score = 0.8 if features.get("is_check") else 0.0 | |
| factors["check_pressure"] = check_score | |
| score += check_score * 0.20 | |
| # Factor 3: Tactical captures available | |
| capture_score = 0.6 if features.get("has_captures") else 0.0 | |
| factors["captures_available"] = capture_score | |
| score += capture_score * 0.15 | |
| # Factor 4: Endgame (few pieces = precise calculation needed) | |
| num_pieces = features.get("num_pieces", 32) | |
| endgame_score = max(0.0, (16 - num_pieces) / 16.0) | |
| factors["endgame_pressure"] = round(endgame_score, 3) | |
| score += endgame_score * 0.20 | |
| # Factor 5: Material imbalance (unbalanced = harder to evaluate) | |
| material = abs(features.get("material_balance", 0.0)) | |
| imbalance_score = min(material / 9.0, 1.0) # queen = 9 | |
| factors["material_imbalance"] = round(imbalance_score, 3) | |
| score += imbalance_score * 0.15 | |
| score = round(min(score, 1.0), 4) | |
| if score >= THRESHOLD_CRITICAL: | |
| level = PositionComplexity.CRITICAL | |
| elif score >= THRESHOLD_COMPLEX: | |
| level = PositionComplexity.COMPLEX | |
| elif score >= 0.25: | |
| level = PositionComplexity.MODERATE | |
| else: | |
| level = PositionComplexity.SIMPLE | |
| recommend = level in (PositionComplexity.COMPLEX, PositionComplexity.CRITICAL) | |
| return ComplexityAnalysis( | |
| fen=features.get("fen", ""), | |
| score=score, | |
| level=level, | |
| factors=factors, | |
| recommend_coaching=recommend, | |
| ) | |
| # Singleton | |
| complexity_analyzer = ComplexityAnalyzer() | |