| 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} |
|
|