|
|
import logging |
|
|
import datetime |
|
|
import random |
|
|
import math |
|
|
from typing import Any, Dict, List, Optional, Set, Tuple |
|
|
import uuid |
|
|
|
|
|
from config import config |
|
|
|
|
|
class VirtualObject: |
|
|
"""Class representing an object in the virtual world.""" |
|
|
|
|
|
def __init__(self, name: str, position: Tuple[float, float], properties: Dict[str, Any] = None): |
|
|
"""Initialize a virtual object with name, position, and properties.""" |
|
|
self.id = str(uuid.uuid4()) |
|
|
self.name = name |
|
|
self.position = position |
|
|
self.properties = properties or {} |
|
|
self.created_at = datetime.datetime.now().isoformat() |
|
|
|
|
|
def update_position(self, new_position: Tuple[float, float]) -> None: |
|
|
"""Update the object's position.""" |
|
|
self.position = new_position |
|
|
|
|
|
def get_property(self, property_name: str, default: Any = None) -> Any: |
|
|
"""Get a property value.""" |
|
|
return self.properties.get(property_name, default) |
|
|
|
|
|
def set_property(self, property_name: str, value: Any) -> None: |
|
|
"""Set a property value.""" |
|
|
self.properties[property_name] = value |
|
|
|
|
|
def to_dict(self) -> Dict[str, Any]: |
|
|
"""Convert object to dictionary.""" |
|
|
return { |
|
|
"id": self.id, |
|
|
"name": self.name, |
|
|
"position": self.position, |
|
|
"properties": self.properties, |
|
|
"created_at": self.created_at |
|
|
} |
|
|
|
|
|
|
|
|
class VirtualLocation: |
|
|
"""Class representing a location in the virtual world.""" |
|
|
|
|
|
def __init__(self, name: str, position: Tuple[float, float], radius: float = 1.0, |
|
|
properties: Dict[str, Any] = None): |
|
|
"""Initialize a virtual location with name, position, radius, and properties.""" |
|
|
self.id = str(uuid.uuid4()) |
|
|
self.name = name |
|
|
self.position = position |
|
|
self.radius = radius |
|
|
self.properties = properties or {} |
|
|
self.created_at = datetime.datetime.now().isoformat() |
|
|
|
|
|
def contains(self, position: Tuple[float, float]) -> bool: |
|
|
"""Check if a position is within this location.""" |
|
|
x1, y1 = self.position |
|
|
x2, y2 = position |
|
|
distance = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) |
|
|
return distance <= self.radius |
|
|
|
|
|
def to_dict(self) -> Dict[str, Any]: |
|
|
"""Convert location to dictionary.""" |
|
|
return { |
|
|
"id": self.id, |
|
|
"name": self.name, |
|
|
"position": self.position, |
|
|
"radius": self.radius, |
|
|
"properties": self.properties, |
|
|
"created_at": self.created_at |
|
|
} |
|
|
|
|
|
|
|
|
class VirtualAgent: |
|
|
"""Class representing an agent's presence in the virtual world.""" |
|
|
|
|
|
def __init__(self, agent_id: str, position: Tuple[float, float], |
|
|
properties: Dict[str, Any] = None): |
|
|
"""Initialize a virtual agent with agent_id, position, and properties.""" |
|
|
self.agent_id = agent_id |
|
|
self.position = position |
|
|
self.properties = properties or {} |
|
|
self.created_at = datetime.datetime.now().isoformat() |
|
|
|
|
|
def update_position(self, new_position: Tuple[float, float]) -> None: |
|
|
"""Update the agent's position.""" |
|
|
self.position = new_position |
|
|
|
|
|
def get_property(self, property_name: str, default: Any = None) -> Any: |
|
|
"""Get a property value.""" |
|
|
return self.properties.get(property_name, default) |
|
|
|
|
|
def set_property(self, property_name: str, value: Any) -> None: |
|
|
"""Set a property value.""" |
|
|
self.properties[property_name] = value |
|
|
|
|
|
def to_dict(self) -> Dict[str, Any]: |
|
|
"""Convert virtual agent to dictionary.""" |
|
|
return { |
|
|
"agent_id": self.agent_id, |
|
|
"position": self.position, |
|
|
"properties": self.properties, |
|
|
"created_at": self.created_at |
|
|
} |
|
|
|
|
|
|
|
|
class VirtualWorld: |
|
|
"""Class representing a virtual world for agent interactions.""" |
|
|
|
|
|
def __init__(self, name: str, size: Tuple[float, float] = (100.0, 100.0)): |
|
|
"""Initialize a virtual world with name and size.""" |
|
|
self.name = name |
|
|
self.size = size |
|
|
self.objects = {} |
|
|
self.locations = {} |
|
|
self.virtual_agents = {} |
|
|
self.created_at = datetime.datetime.now().isoformat() |
|
|
self.logger = logging.getLogger(f"virtual_world.{name}") |
|
|
self.logger.info(f"Virtual world {name} initialized with size {size}") |
|
|
|
|
|
def add_object(self, obj: VirtualObject) -> str: |
|
|
"""Add an object to the world.""" |
|
|
self.objects[obj.id] = obj |
|
|
self.logger.info(f"Added object {obj.name} at position {obj.position}") |
|
|
return obj.id |
|
|
|
|
|
def remove_object(self, object_id: str) -> bool: |
|
|
"""Remove an object from the world.""" |
|
|
if object_id not in self.objects: |
|
|
return False |
|
|
|
|
|
obj = self.objects[object_id] |
|
|
del self.objects[object_id] |
|
|
|
|
|
self.logger.info(f"Removed object {obj.name}") |
|
|
return True |
|
|
|
|
|
def add_location(self, location: VirtualLocation) -> str: |
|
|
"""Add a location to the world.""" |
|
|
self.locations[location.id] = location |
|
|
self.logger.info(f"Added location {location.name} at position {location.position}") |
|
|
return location.id |
|
|
|
|
|
def remove_location(self, location_id: str) -> bool: |
|
|
"""Remove a location from the world.""" |
|
|
if location_id not in self.locations: |
|
|
return False |
|
|
|
|
|
location = self.locations[location_id] |
|
|
del self.locations[location_id] |
|
|
|
|
|
self.logger.info(f"Removed location {location.name}") |
|
|
return True |
|
|
|
|
|
def add_agent(self, agent_id: str, position: Tuple[float, float], |
|
|
properties: Dict[str, Any] = None) -> bool: |
|
|
"""Add an agent to the world.""" |
|
|
if agent_id in self.virtual_agents: |
|
|
self.logger.warning(f"Agent {agent_id} is already in the world") |
|
|
return False |
|
|
|
|
|
virtual_agent = VirtualAgent(agent_id, position, properties) |
|
|
self.virtual_agents[agent_id] = virtual_agent |
|
|
|
|
|
self.logger.info(f"Added agent {agent_id} at position {position}") |
|
|
return True |
|
|
|
|
|
def remove_agent(self, agent_id: str) -> bool: |
|
|
"""Remove an agent from the world.""" |
|
|
if agent_id not in self.virtual_agents: |
|
|
return False |
|
|
|
|
|
del self.virtual_agents[agent_id] |
|
|
|
|
|
self.logger.info(f"Removed agent {agent_id}") |
|
|
return True |
|
|
|
|
|
def move_agent(self, agent_id: str, new_position: Tuple[float, float]) -> bool: |
|
|
"""Move an agent to a new position.""" |
|
|
if agent_id not in self.virtual_agents: |
|
|
self.logger.warning(f"Agent {agent_id} is not in the world") |
|
|
return False |
|
|
|
|
|
|
|
|
x, y = new_position |
|
|
width, height = self.size |
|
|
x = max(0, min(width, x)) |
|
|
y = max(0, min(height, y)) |
|
|
|
|
|
virtual_agent = self.virtual_agents[agent_id] |
|
|
old_position = virtual_agent.position |
|
|
virtual_agent.update_position((x, y)) |
|
|
|
|
|
self.logger.info(f"Moved agent {agent_id} from {old_position} to {(x, y)}") |
|
|
return True |
|
|
|
|
|
def get_objects_near(self, position: Tuple[float, float], radius: float) -> List[VirtualObject]: |
|
|
"""Get objects near a position within a radius.""" |
|
|
nearby_objects = [] |
|
|
x1, y1 = position |
|
|
|
|
|
for obj in self.objects.values(): |
|
|
x2, y2 = obj.position |
|
|
distance = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) |
|
|
if distance <= radius: |
|
|
nearby_objects.append(obj) |
|
|
|
|
|
return nearby_objects |
|
|
|
|
|
def get_agents_near(self, position: Tuple[float, float], radius: float) -> List[str]: |
|
|
"""Get agent IDs near a position within a radius.""" |
|
|
nearby_agents = [] |
|
|
x1, y1 = position |
|
|
|
|
|
for agent_id, virtual_agent in self.virtual_agents.items(): |
|
|
x2, y2 = virtual_agent.position |
|
|
distance = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) |
|
|
if distance <= radius: |
|
|
nearby_agents.append(agent_id) |
|
|
|
|
|
return nearby_agents |
|
|
|
|
|
def get_location_at(self, position: Tuple[float, float]) -> Optional[VirtualLocation]: |
|
|
"""Get the location at a position.""" |
|
|
for location in self.locations.values(): |
|
|
if location.contains(position): |
|
|
return location |
|
|
return None |
|
|
|
|
|
def get_agent_location(self, agent_id: str) -> Optional[VirtualLocation]: |
|
|
"""Get the location of an agent.""" |
|
|
if agent_id not in self.virtual_agents: |
|
|
return None |
|
|
|
|
|
virtual_agent = self.virtual_agents[agent_id] |
|
|
return self.get_location_at(virtual_agent.position) |
|
|
|
|
|
def get_distance(self, position1: Tuple[float, float], position2: Tuple[float, float]) -> float: |
|
|
"""Calculate the distance between two positions.""" |
|
|
x1, y1 = position1 |
|
|
x2, y2 = position2 |
|
|
return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) |
|
|
|
|
|
def get_agent_distance(self, agent_id1: str, agent_id2: str) -> Optional[float]: |
|
|
"""Calculate the distance between two agents.""" |
|
|
if agent_id1 not in self.virtual_agents or agent_id2 not in self.virtual_agents: |
|
|
return None |
|
|
|
|
|
pos1 = self.virtual_agents[agent_id1].position |
|
|
pos2 = self.virtual_agents[agent_id2].position |
|
|
return self.get_distance(pos1, pos2) |
|
|
|
|
|
def can_agents_interact(self, agent_id1: str, agent_id2: str, |
|
|
max_distance: float = 5.0) -> bool: |
|
|
"""Check if two agents can interact based on distance.""" |
|
|
distance = self.get_agent_distance(agent_id1, agent_id2) |
|
|
if distance is None: |
|
|
return False |
|
|
return distance <= max_distance |
|
|
|
|
|
def get_random_position(self) -> Tuple[float, float]: |
|
|
"""Get a random position within the world.""" |
|
|
width, height = self.size |
|
|
x = random.uniform(0, width) |
|
|
y = random.uniform(0, height) |
|
|
return (x, y) |
|
|
|
|
|
def to_dict(self) -> Dict[str, Any]: |
|
|
"""Convert virtual world to dictionary representation.""" |
|
|
return { |
|
|
"name": self.name, |
|
|
"size": self.size, |
|
|
"object_count": len(self.objects), |
|
|
"location_count": len(self.locations), |
|
|
"agent_count": len(self.virtual_agents), |
|
|
"created_at": self.created_at |
|
|
} |
|
|
|
|
|
|