villsim/backend/api/schemas.py
2026-01-19 22:55:26 +03:00

240 lines
5.7 KiB
Python

"""Pydantic schemas for API request/response models."""
from typing import Optional
from pydantic import BaseModel, Field
# ============== Resource Schemas ==============
class ResourceSchema(BaseModel):
"""Schema for a resource item."""
type: str
quantity: int
created_turn: int
decay_rate: Optional[int] = None
# ============== Agent Schemas ==============
class PositionSchema(BaseModel):
"""Schema for agent position (float for smooth movement)."""
x: float
y: float
class StatsSchema(BaseModel):
"""Schema for agent vital stats."""
energy: int
hunger: int
thirst: int
heat: int
max_energy: int
max_hunger: int
max_thirst: int
max_heat: int
class AgentActionSchema(BaseModel):
"""Schema for current agent action."""
action_type: str
target_position: Optional[PositionSchema] = None
target_resource: Optional[str] = None
progress: float
is_moving: bool
message: str
class AgentResponse(BaseModel):
"""Schema for agent data."""
id: str
name: str
profession: str
position: PositionSchema
home_position: PositionSchema
stats: StatsSchema
inventory: list[ResourceSchema]
money: int
is_alive: bool
is_corpse: bool = False
can_act: bool
current_action: AgentActionSchema
last_action_result: str
death_turn: int = -1
death_reason: str = ""
# Age system
age: int = 25
max_age: int = 70
age_category: str = "prime"
birth_day: int = 0
generation: int = 0
parent_ids: list[str] = []
children_count: int = 0
# Age modifiers
skill_modifier: float = 1.0
energy_cost_modifier: float = 1.0
learning_modifier: float = 1.0
# Personality and skills
personality: dict = {}
skills: dict = {}
actions_performed: dict = {}
total_trades: int = 0
total_money_earned: int = 0
action_history: list = []
# ============== Market Schemas ==============
class OrderSchema(BaseModel):
"""Schema for a market order."""
id: str
seller_id: str
resource_type: str
quantity: int
price_per_unit: int
total_price: int
created_turn: int
status: str
turns_without_sale: int
class MarketPriceSchema(BaseModel):
"""Schema for market price summary."""
lowest_price: Optional[int]
highest_price: Optional[int]
total_available: int
num_orders: int
class TradeResultSchema(BaseModel):
"""Schema for a trade result."""
success: bool
order_id: str = ""
buyer_id: str = ""
seller_id: str = ""
resource_type: Optional[str] = None
quantity: int = 0
total_paid: int = 0
message: str = ""
class MarketStateResponse(BaseModel):
"""Schema for market state."""
orders: list[OrderSchema]
prices: dict[str, MarketPriceSchema]
recent_trades: list[TradeResultSchema]
# ============== World Schemas ==============
class WorldSizeSchema(BaseModel):
"""Schema for world dimensions."""
width: int
height: int
class StatisticsSchema(BaseModel):
"""Schema for world statistics."""
current_turn: int
current_day: int
step_in_day: int
time_of_day: str
living_agents: int
total_agents_spawned: int
total_agents_died: int
total_births: int = 0
total_money_in_circulation: int
professions: dict[str, int]
# Wealth inequality metrics
avg_money: float = 0.0
median_money: int = 0
richest_agent: int = 0
poorest_agent: int = 0
gini_coefficient: float = 0.0
# Age demographics
age_distribution: dict[str, int] = {}
avg_age: float = 0.0
oldest_agent: int = 0
youngest_agent: int = 0
generations: dict[int, int] = {}
# Death statistics
deaths_by_cause: dict[str, int] = {}
# Village storage
village_storage: dict[str, int] = {}
class ActionLogSchema(BaseModel):
"""Schema for an action in the turn log."""
agent_id: str
agent_name: str
decision: dict
result: Optional[dict] = None
class TurnLogSchema(BaseModel):
"""Schema for a turn log entry."""
turn: int
agent_actions: list[ActionLogSchema]
deaths: list[str]
births: list[str] = []
trades: list[dict]
resources_produced: dict[str, int] = {}
resources_consumed: dict[str, int] = {}
resources_spoiled: dict[str, int] = {}
day_events: dict = {}
class ResourceStatsSchema(BaseModel):
"""Schema for resource statistics."""
produced: dict[str, int] = {}
consumed: dict[str, int] = {}
spoiled: dict[str, int] = {}
in_inventory: dict[str, int] = {}
in_market: dict[str, int] = {}
class WorldStateResponse(BaseModel):
"""Full world state response."""
turn: int
day: int
step_in_day: int
time_of_day: str
world_size: WorldSizeSchema
agents: list[AgentResponse]
statistics: StatisticsSchema
market: MarketStateResponse
mode: str
is_running: bool
recent_logs: list[TurnLogSchema]
resource_stats: ResourceStatsSchema = ResourceStatsSchema()
# ============== Control Schemas ==============
class ControlResponse(BaseModel):
"""Response for control operations."""
success: bool
message: str
turn: Optional[int] = None
mode: Optional[str] = None
class SetModeRequest(BaseModel):
"""Request to set simulation mode."""
mode: str = Field(..., pattern="^(manual|auto)$")
class InitializeRequest(BaseModel):
"""Request to initialize simulation."""
num_agents: int = Field(default=8, ge=1, le=50)
world_width: int = Field(default=20, ge=5, le=100)
world_height: int = Field(default=20, ge=5, le=100)
# ============== Error Schemas ==============
class ErrorResponse(BaseModel):
"""Error response."""
error: str
detail: Optional[str] = None