import re from datetime import datetime, timezone from typing import List, Optional from pydantic import BaseModel, Field, field_validator class PlayerCreate(BaseModel): name: str = Field(..., min_length=1, max_length=32, description="Display name of the player") color: str = Field(..., description="Hex color code (e.g. #FF5733) or valid CSS color name") @field_validator("name") @classmethod def validate_name(cls, v: str) -> str: cleaned = v.strip() if not cleaned: raise ValueError("Player name cannot be empty or only whitespace") return cleaned @field_validator("color") @classmethod def validate_color(cls, v: str) -> str: cleaned = v.strip() # Accept #RRGGBB, #RGB, or standard alphanumeric color names if re.match(r"^#(?:[0-9a-fA-F]{3}){1,2}$", cleaned): return cleaned.upper() if re.match(r"^[a-zA-Z]{3,20}$", cleaned): return cleaned.lower() raise ValueError("Color must be a valid hex code (e.g. #FF4444) or color name (e.g. crimson)") class Player(BaseModel): id: str name: str color: str x: int y: int created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) class BoardConfig(BaseModel): min_x: int = 0 max_x: int = 64 min_y: int = 0 max_y: int = 64 grid_cells_x: int = 64 grid_cells_y: int = 64 class BoardState(BaseModel): config: BoardConfig player_count: int players: List[Player] class ApiResponse(BaseModel): success: bool message: str data: Optional[dict] = None