strat-gameplay-webapp/backend/app/config/league_configs.py
Cal Corum 5d5c13f2b8 CLAUDE: Implement Week 6 league configuration and play outcome systems
Week 6 Progress: 75% Complete

## Components Implemented

### 1. League Configuration System 
- Created BaseGameConfig abstract class for league-agnostic rules
- Implemented SbaConfig and PdConfig with league-specific settings
- Immutable configs (frozen=True) with singleton registry
- 28 unit tests, all passing

Files:
- backend/app/config/base_config.py
- backend/app/config/league_configs.py
- backend/tests/unit/config/test_league_configs.py

### 2. PlayOutcome Enum 
- Universal enum for all play outcomes (both SBA and PD)
- Helper methods: is_hit(), is_out(), is_uncapped(), is_interrupt()
- Supports standard hits, uncapped hits, interrupt plays, ballpark power
- 30 unit tests, all passing

Files:
- backend/app/config/result_charts.py
- backend/tests/unit/config/test_play_outcome.py

### 3. Player Model Refinements 
- Fixed PdPlayer.id field mapping (player_id → id)
- Improved field docstrings for image types
- Fixed position checking logic in SBA helper methods
- Added safety checks for missing image data

Files:
- backend/app/models/player_models.py (updated)

### 4. Documentation 
- Updated backend/CLAUDE.md with Week 6 section
- Documented card-based resolution mechanics
- Detailed config system and PlayOutcome usage

## Architecture Decisions

1. **Card-Based Resolution**: Both SBA and PD use same mechanics
   - 1d6 (column) + 2d6 (row) + 1d20 (split resolution)
   - PD: Digitized cards with auto-resolution
   - SBA: Manual entry from physical cards

2. **Immutable Configs**: Prevent accidental modification using Pydantic frozen

3. **Universal PlayOutcome**: Single enum for both leagues reduces duplication

## Testing
- Total: 58 tests, all passing
- Config tests: 28
- PlayOutcome tests: 30

## Remaining Work (25%)
- Update dice system (check_d20 → chaos_d20)
- Integrate PlayOutcome into PlayResolver
- Add Play.metadata support for uncapped hits

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 22:46:12 -05:00

108 lines
2.9 KiB
Python

"""
League-specific configuration implementations.
Provides concrete configs for SBA and PD leagues with their unique rules,
API endpoints, and feature flags.
Author: Claude
Date: 2025-10-28
"""
import logging
from typing import Dict
from app.config.base_config import BaseGameConfig
logger = logging.getLogger(f'{__name__}.LeagueConfigs')
class SbaConfig(BaseGameConfig):
"""
SBA League configuration.
Features:
- Manual result selection after dice roll
- Simple player data model
- Standard baseball rules
"""
league_id: str = "sba"
# SBA-specific features
player_selection_mode: str = "manual" # Players manually select from chart
def get_result_chart_name(self) -> str:
"""Use SBA standard result chart."""
return "sba_standard_v1"
def supports_manual_result_selection(self) -> bool:
"""SBA players manually pick results from chart."""
return True
def get_api_base_url(self) -> str:
"""SBA API base URL."""
return "https://api.sba.manticorum.com"
class PdConfig(BaseGameConfig):
"""
Paper Dynasty League configuration.
Features:
- Flexible result selection (manual or auto via scouting)
- Complex scouting data model
- Cardset validation
- Advanced analytics
"""
league_id: str = "pd"
# PD-specific features
player_selection_mode: str = "flexible" # Manual or auto via scouting model
use_scouting_model: bool = True # Use detailed ratings for auto-resolution
cardset_validation: bool = True # Validate cards against approved cardsets
# Advanced features
detailed_analytics: bool = True # Track advanced stats (WPA, RE24, etc.)
wpa_calculation: bool = True # Calculate win probability added
def get_result_chart_name(self) -> str:
"""Use PD standard result chart."""
return "pd_standard_v1"
def supports_manual_result_selection(self) -> bool:
"""PD supports manual selection (though auto is also available)."""
return True
def get_api_base_url(self) -> str:
"""PD API base URL."""
return "https://pd.manticorum.com"
# ==================== Config Registry ====================
LEAGUE_CONFIGS: Dict[str, BaseGameConfig] = {
"sba": SbaConfig(),
"pd": PdConfig()
}
def get_league_config(league_id: str) -> BaseGameConfig:
"""
Get configuration for specified league.
Args:
league_id: League identifier ('sba' or 'pd')
Returns:
League-specific config instance
Raises:
ValueError: If league_id is not recognized
"""
config = LEAGUE_CONFIGS.get(league_id)
if not config:
logger.error(f"Unknown league ID: {league_id}")
raise ValueError(f"Unknown league: {league_id}. Valid leagues: {list(LEAGUE_CONFIGS.keys())}")
logger.debug(f"Retrieved config for league: {league_id}")
return config