from __future__ import annotations import time from dataclasses import dataclass, field from .config import GameConfig from .tile import Tile from ..agent.state import AgentState @dataclass class Environment: grid: dict[tuple[int, int], Tile] = field(default_factory=dict) agents: dict[str, AgentState] = field(default_factory=dict) turn: int = 0 config: GameConfig = field(default_factory=GameConfig) def get_tile(self, x: int, y: int) -> Tile: return self.grid.get((x, y), Tile(terrain="void")) def is_in_bounds(self, x: int, y: int) -> bool: return 0 <= x < self.config.grid_size and 0 <= y < self.config.grid_size def is_empty(self, x: int, y: int) -> bool: return self.is_in_bounds(x, y) and not any( a.pos == [x, y] and a.alive for a in self.agents.values() ) def alive_agents(self) -> list[AgentState]: return [a for a in self.agents.values() if a.alive] def get_ability_cooldown(self, name: str) -> int: from .ability_registry import ABILITY_REGISTRY ab = ABILITY_REGISTRY.get(name) return ab.cooldown if ab else 0 def get_ability_description(self, name: str) -> str: from .ability_registry import ABILITY_REGISTRY ab = ABILITY_REGISTRY.get(name) return ab.description if ab else "" def execute(self, aid: str, tool_name: str, args: dict) -> dict: from ..tools import ALL_TOOLS t0 = time.time() tool_cls = ALL_TOOLS.get(tool_name) if not tool_cls: elapsed = round((time.time() - t0) * 1000) return {"text": f"Unknown tool: {tool_name}", "time_ms": elapsed} text = tool_cls.run(self, aid, args) elapsed = round((time.time() - t0) * 1000) return {"text": text, "time_ms": elapsed}