Daniel Ari Friedman e555897efa Updates
2025-02-07 09:36:14 -08:00

164 строки
5.3 KiB
Python

"""
Main entry point for the ant colony simulation.
"""
import argparse
import yaml
import numpy as np
from ant_colony.visualization import SimulationRenderer
from ant_colony.agents import Nestmate, Position, TaskType
from dataclasses import dataclass
from typing import List
@dataclass
class FoodSource:
"""Represents a food source in the environment."""
position: Position
size: float
value: float
remaining: float
@dataclass
class Obstacle:
"""Represents an obstacle in the environment."""
position: Position
size: float
class Simulation:
"""Main simulation class."""
def __init__(self, config_path: str):
"""Initialize simulation with configuration."""
with open(config_path, 'r') as f:
self.config = yaml.safe_load(f)
# Set random seed
np.random.seed(self.config['simulation']['random_seed'])
# Initialize environment
self.env_size = self.config['environment']['size']
self.nest_location = self.config['environment']['nest_location']
# Initialize agents
self.agents = self._create_agents()
# Initialize resources
self.food_sources = self._create_food_sources()
self.obstacles = self._create_obstacles()
# Initialize pheromone grids
self.pheromones = {
'food': np.zeros(self.env_size),
'home': np.zeros(self.env_size)
}
# Setup visualization if enabled
if self.config['visualization']['enabled']:
self.renderer = SimulationRenderer(self.config)
else:
self.renderer = None
def _create_agents(self) -> List[Nestmate]:
"""Create initial population of agents."""
agents = []
for _ in range(self.config['colony']['initial_population']):
# Start agents near nest
x = self.nest_location[0] + np.random.normal(0, 2)
y = self.nest_location[1] + np.random.normal(0, 2)
theta = np.random.uniform(0, 2 * np.pi)
agent = Nestmate(self.config['agent'])
agent.position = Position(x, y, theta)
agents.append(agent)
return agents
def _create_food_sources(self) -> List[FoodSource]:
"""Create initial food sources."""
sources = []
for _ in range(self.config['environment']['food_sources']['count']):
x = np.random.uniform(0, self.env_size[0])
y = np.random.uniform(0, self.env_size[1])
size = np.random.uniform(*self.config['environment']['food_sources']['size_range'])
value = np.random.uniform(*self.config['environment']['food_sources']['value_range'])
source = FoodSource(
position=Position(x, y, 0),
size=size,
value=value,
remaining=value
)
sources.append(source)
return sources
def _create_obstacles(self) -> List[Obstacle]:
"""Create initial obstacles."""
obstacles = []
for _ in range(self.config['environment']['obstacles']['count']):
x = np.random.uniform(0, self.env_size[0])
y = np.random.uniform(0, self.env_size[1])
size = np.random.uniform(*self.config['environment']['obstacles']['size_range'])
obstacle = Obstacle(
position=Position(x, y, 0),
size=size
)
obstacles.append(obstacle)
return obstacles
def update(self) -> None:
"""Update simulation state for one timestep."""
dt = self.config['simulation']['timestep']
# Update agents
world_state = {
'agents': self.agents,
'resources': self.food_sources,
'obstacles': self.obstacles,
'pheromones': self.pheromones
}
for agent in self.agents:
agent.update(dt, world_state)
# Update pheromones
decay = self.config['environment']['pheromone_decay']
self.pheromones['food'] *= decay
self.pheromones['home'] *= decay
# Update visualization
if self.renderer and self.config['visualization']['enabled']:
self.renderer.update(world_state)
def run(self) -> None:
"""Run the simulation."""
max_steps = self.config['simulation']['max_steps']
try:
for step in range(max_steps):
self.update()
if step % 100 == 0:
print(f"Step {step}/{max_steps}")
except KeyboardInterrupt:
print("\nSimulation interrupted by user")
finally:
if self.renderer:
self.renderer.show()
def main():
"""Main entry point."""
parser = argparse.ArgumentParser(description="Ant Colony Simulation")
parser.add_argument('--config', type=str, required=True,
help='Path to configuration file')
args = parser.parse_args()
simulation = Simulation(args.config)
simulation.run()
if __name__ == '__main__':
main()