Add EntityConfig for entity hyperparameters and integrate into simulation configuration
This commit is contained in:
parent
19b946949d
commit
e2d56ffb76
@ -5,7 +5,8 @@ from .simulation_config import (
|
|||||||
HeadlessConfig,
|
HeadlessConfig,
|
||||||
InteractiveConfig,
|
InteractiveConfig,
|
||||||
ExperimentConfig,
|
ExperimentConfig,
|
||||||
OutputConfig
|
OutputConfig,
|
||||||
|
EntityConfig
|
||||||
)
|
)
|
||||||
from .config_loader import ConfigLoader
|
from .config_loader import ConfigLoader
|
||||||
|
|
||||||
@ -15,5 +16,6 @@ __all__ = [
|
|||||||
'InteractiveConfig',
|
'InteractiveConfig',
|
||||||
'ExperimentConfig',
|
'ExperimentConfig',
|
||||||
'OutputConfig',
|
'OutputConfig',
|
||||||
|
'EntityConfig',
|
||||||
'ConfigLoader'
|
'ConfigLoader'
|
||||||
]
|
]
|
||||||
@ -101,7 +101,14 @@ class ConfigLoader:
|
|||||||
|
|
||||||
# Extract simulation config if present
|
# Extract simulation config if present
|
||||||
sim_data = data.get('simulation', {})
|
sim_data = data.get('simulation', {})
|
||||||
simulation_config = SimulationConfig(**sim_data)
|
|
||||||
|
# Extract entities config if present
|
||||||
|
entities_data = sim_data.get('entities', {})
|
||||||
|
entities_config = EntityConfig(**entities_data)
|
||||||
|
|
||||||
|
# Create simulation config with entities
|
||||||
|
sim_data_without_entities = {k: v for k, v in sim_data.items() if k != 'entities'}
|
||||||
|
simulation_config = SimulationConfig(entities=entities_config, **sim_data_without_entities)
|
||||||
|
|
||||||
return HeadlessConfig(
|
return HeadlessConfig(
|
||||||
max_ticks=data.get('max_ticks'),
|
max_ticks=data.get('max_ticks'),
|
||||||
@ -115,7 +122,14 @@ class ConfigLoader:
|
|||||||
"""Convert dictionary to InteractiveConfig."""
|
"""Convert dictionary to InteractiveConfig."""
|
||||||
# Extract simulation config if present
|
# Extract simulation config if present
|
||||||
sim_data = data.get('simulation', {})
|
sim_data = data.get('simulation', {})
|
||||||
simulation_config = SimulationConfig(**sim_data)
|
|
||||||
|
# Extract entities config if present
|
||||||
|
entities_data = sim_data.get('entities', {})
|
||||||
|
entities_config = EntityConfig(**entities_data)
|
||||||
|
|
||||||
|
# Create simulation config with entities
|
||||||
|
sim_data_without_entities = {k: v for k, v in sim_data.items() if k != 'entities'}
|
||||||
|
simulation_config = SimulationConfig(entities=entities_config, **sim_data_without_entities)
|
||||||
|
|
||||||
return InteractiveConfig(
|
return InteractiveConfig(
|
||||||
window_width=data.get('window_width', 0),
|
window_width=data.get('window_width', 0),
|
||||||
@ -190,5 +204,5 @@ class ConfigLoader:
|
|||||||
print(f"Sample configs created in {output_path}")
|
print(f"Sample configs created in {output_path}")
|
||||||
|
|
||||||
|
|
||||||
# Import OutputConfig for the loader
|
# Import Config classes for the loader
|
||||||
from .simulation_config import OutputConfig, SimulationConfig
|
from .simulation_config import OutputConfig, SimulationConfig, EntityConfig
|
||||||
@ -1,21 +1,50 @@
|
|||||||
"""Simulation configuration classes for different modes."""
|
"""Simulation configuration classes for different modes."""
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import List, Optional
|
from typing import List, Optional, Dict, Any
|
||||||
from config.constants import *
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class EntityConfig:
|
||||||
|
"""Configuration for entity hyperparameters."""
|
||||||
|
|
||||||
|
# Global entity settings (apply to all entity types unless overridden)
|
||||||
|
max_acceleration: float = 0.125
|
||||||
|
max_angular_acceleration: float = 0.25
|
||||||
|
max_velocity: float = 1.0
|
||||||
|
max_rotational_velocity: float = 3.0
|
||||||
|
|
||||||
|
# Entity type specific configs (all entity parameters should be defined here)
|
||||||
|
entity_types: Dict[str, Dict[str, Any]] = field(default_factory=lambda: {
|
||||||
|
"default_cell": {
|
||||||
|
"reproduction_energy": 1700,
|
||||||
|
"starting_energy": 1000,
|
||||||
|
"interaction_radius": 50,
|
||||||
|
"drag_coefficient": 0.02,
|
||||||
|
"energy_cost_base": 1.5,
|
||||||
|
"neural_network_complexity_cost": 0.08,
|
||||||
|
"movement_cost": 0.25,
|
||||||
|
"food_energy_value": 140,
|
||||||
|
"max_visual_width": 10,
|
||||||
|
"reproduction_count": 2,
|
||||||
|
"mutation_rate": 0.05,
|
||||||
|
"offspring_offset_range": 10
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SimulationConfig:
|
class SimulationConfig:
|
||||||
"""Configuration for simulation setup."""
|
"""Configuration for simulation setup."""
|
||||||
grid_width: int = GRID_WIDTH
|
grid_width: int = 50
|
||||||
grid_height: int = GRID_HEIGHT
|
grid_height: int = 50
|
||||||
cell_size: int = CELL_SIZE
|
cell_size: int = 20
|
||||||
initial_cells: int = 50
|
initial_cells: int = 50
|
||||||
initial_food: int = FOOD_OBJECTS_COUNT
|
initial_food: int = 500
|
||||||
food_spawning: bool = FOOD_SPAWNING
|
food_spawning: bool = True
|
||||||
random_seed: int = RANDOM_SEED
|
random_seed: int = 0
|
||||||
default_tps: float = DEFAULT_TPS
|
default_tps: float = 40.0
|
||||||
|
entities: EntityConfig = field(default_factory=EntityConfig)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -44,16 +73,7 @@ class HeadlessConfig:
|
|||||||
output: OutputConfig = field(default_factory=OutputConfig)
|
output: OutputConfig = field(default_factory=OutputConfig)
|
||||||
|
|
||||||
# Simulation core config
|
# Simulation core config
|
||||||
simulation: SimulationConfig = field(default_factory=lambda: SimulationConfig(
|
simulation: SimulationConfig = field(default_factory=SimulationConfig)
|
||||||
grid_width=GRID_WIDTH,
|
|
||||||
grid_height=GRID_HEIGHT,
|
|
||||||
cell_size=CELL_SIZE,
|
|
||||||
initial_cells=50,
|
|
||||||
initial_food=FOOD_OBJECTS_COUNT,
|
|
||||||
food_spawning=FOOD_SPAWNING,
|
|
||||||
random_seed=RANDOM_SEED,
|
|
||||||
default_tps=DEFAULT_TPS
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -75,16 +95,7 @@ class InteractiveConfig:
|
|||||||
console_height: int = 120
|
console_height: int = 120
|
||||||
|
|
||||||
# Simulation core config
|
# Simulation core config
|
||||||
simulation: SimulationConfig = field(default_factory=lambda: SimulationConfig(
|
simulation: SimulationConfig = field(default_factory=lambda: SimulationConfig(initial_cells=350))
|
||||||
grid_width=GRID_WIDTH,
|
|
||||||
grid_height=GRID_HEIGHT,
|
|
||||||
cell_size=CELL_SIZE,
|
|
||||||
initial_cells=350,
|
|
||||||
initial_food=FOOD_OBJECTS_COUNT,
|
|
||||||
food_spawning=FOOD_SPAWNING,
|
|
||||||
random_seed=RANDOM_SEED,
|
|
||||||
default_tps=DEFAULT_TPS
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
import pygame
|
import pygame
|
||||||
import math
|
import math
|
||||||
from config.constants import *
|
from config.constants import *
|
||||||
from world.base.brain import CellBrain
|
|
||||||
from world.objects import DefaultCell, FoodObject
|
from world.objects import DefaultCell, FoodObject
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ from world.world import World, Position, Rotation
|
|||||||
from world.simulation_interface import Camera
|
from world.simulation_interface import Camera
|
||||||
from .event_bus import EventBus, EventType, Event
|
from .event_bus import EventBus, EventType, Event
|
||||||
from .timing import TimingController
|
from .timing import TimingController
|
||||||
from config.constants import *
|
from config.constants import RENDER_BUFFER
|
||||||
from config.simulation_config import SimulationConfig
|
from config.simulation_config import SimulationConfig
|
||||||
|
|
||||||
|
|
||||||
@ -82,7 +82,8 @@ class SimulationCore:
|
|||||||
x=random.randint(-half_width // 2, half_width // 2),
|
x=random.randint(-half_width // 2, half_width // 2),
|
||||||
y=random.randint(-half_height // 2, half_height // 2)
|
y=random.randint(-half_height // 2, half_height // 2)
|
||||||
),
|
),
|
||||||
Rotation(angle=0)
|
Rotation(angle=0),
|
||||||
|
entity_config=getattr(self.config, 'entities', None)
|
||||||
)
|
)
|
||||||
# Mutate the initial behavioral model for variety
|
# Mutate the initial behavioral model for variety
|
||||||
cell.behavioral_model = cell.behavioral_model.mutate(3)
|
cell.behavioral_model = cell.behavioral_model.mutate(3)
|
||||||
|
|||||||
@ -4,23 +4,22 @@ import sys
|
|||||||
|
|
||||||
from pygame_gui import UIManager
|
from pygame_gui import UIManager
|
||||||
|
|
||||||
from world.simulation_interface import Camera
|
from config.constants import BLACK, DEFAULT_TPS, MAX_FPS
|
||||||
from config.constants import *
|
|
||||||
from core.input_handler import InputHandler
|
from core.input_handler import InputHandler
|
||||||
from core.renderer import Renderer
|
from core.renderer import Renderer
|
||||||
from core.simulation_core import SimulationCore, SimulationConfig
|
from core.simulation_core import SimulationCore
|
||||||
from core.event_bus import EventBus
|
from core.event_bus import EventBus
|
||||||
from ui.hud import HUD
|
from ui.hud import HUD
|
||||||
|
|
||||||
import cProfile
|
import cProfile
|
||||||
import pstats
|
|
||||||
|
|
||||||
|
|
||||||
class SimulationEngine:
|
class SimulationEngine:
|
||||||
"""Interactive simulation engine with UI (wrapper around SimulationCore)."""
|
"""Interactive simulation engine with UI (wrapper around SimulationCore)."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, config=None):
|
||||||
pygame.init()
|
pygame.init()
|
||||||
|
self.config = config
|
||||||
self.event_bus = EventBus()
|
self.event_bus = EventBus()
|
||||||
self._init_window()
|
self._init_window()
|
||||||
self._init_simulation()
|
self._init_simulation()
|
||||||
@ -47,11 +46,23 @@ class SimulationEngine:
|
|||||||
|
|
||||||
def _init_window(self):
|
def _init_window(self):
|
||||||
info = pygame.display.Info()
|
info = pygame.display.Info()
|
||||||
self.window_width = int(info.current_w // 1.5)
|
|
||||||
self.window_height = int(info.current_h // 1.5)
|
# Use config or defaults
|
||||||
|
if self.config:
|
||||||
|
self.window_width = self.config.window_width or int(info.current_w // 1.5)
|
||||||
|
self.window_height = self.config.window_height or int(info.current_h // 1.5)
|
||||||
|
vsync = 1 if self.config.vsync else 0
|
||||||
|
resizable = self.config.resizable
|
||||||
|
else:
|
||||||
|
self.window_width = int(info.current_w // 1.5)
|
||||||
|
self.window_height = int(info.current_h // 1.5)
|
||||||
|
vsync = 1
|
||||||
|
resizable = True
|
||||||
|
|
||||||
|
screen_flags = pygame.RESIZABLE if resizable else 0
|
||||||
self.screen = pygame.display.set_mode(
|
self.screen = pygame.display.set_mode(
|
||||||
(self.window_width, self.window_height),
|
(self.window_width, self.window_height),
|
||||||
pygame.RESIZABLE, vsync=1
|
screen_flags, vsync=vsync
|
||||||
)
|
)
|
||||||
pygame.display.set_caption("Dynamic Abstraction System Testing")
|
pygame.display.set_caption("Dynamic Abstraction System Testing")
|
||||||
self.clock = pygame.time.Clock()
|
self.clock = pygame.time.Clock()
|
||||||
@ -67,26 +78,30 @@ class SimulationEngine:
|
|||||||
# Set HUD reference in input handler after both are created
|
# Set HUD reference in input handler after both are created
|
||||||
self.input_handler.set_hud(self.hud)
|
self.input_handler.set_hud(self.hud)
|
||||||
|
|
||||||
|
# Pass config settings to HUD and input handler
|
||||||
|
if self.config:
|
||||||
|
self.input_handler.show_grid = self.config.show_grid
|
||||||
|
self.input_handler.show_interaction_radius = self.config.show_interaction_radius
|
||||||
|
self.input_handler.show_legend = self.config.show_legend
|
||||||
|
|
||||||
self._update_simulation_view()
|
self._update_simulation_view()
|
||||||
|
|
||||||
def _init_simulation(self):
|
def _init_simulation(self):
|
||||||
# Initialize default sim view rect (will be updated by _init_ui)
|
# Initialize default sim view rect (will be updated by _init_ui)
|
||||||
self.sim_view_width = self.window_width - 400 # Rough estimate for inspector width
|
if self.config:
|
||||||
self.sim_view_height = self.window_height - 200 # Rough estimate for control bar height
|
self.sim_view_width = self.window_width - self.config.inspector_width
|
||||||
|
self.sim_view_height = self.window_height - self.config.control_bar_height
|
||||||
|
else:
|
||||||
|
self.sim_view_width = self.window_width - 400 # Rough estimate for inspector width
|
||||||
|
self.sim_view_height = self.window_height - 200 # Rough estimate for control bar height
|
||||||
self.sim_view = pygame.Surface((self.sim_view_width, self.sim_view_height))
|
self.sim_view = pygame.Surface((self.sim_view_width, self.sim_view_height))
|
||||||
self.sim_view_rect = self.sim_view.get_rect(topleft=(200, 48)) # Rough estimate
|
self.sim_view_rect = self.sim_view.get_rect(topleft=(200, 48)) # Rough estimate
|
||||||
|
|
||||||
# Create simulation core
|
# Create simulation core with config
|
||||||
sim_config = SimulationConfig(
|
if self.config and self.config.simulation:
|
||||||
grid_width=GRID_WIDTH,
|
sim_config = self.config.simulation
|
||||||
grid_height=GRID_HEIGHT,
|
else:
|
||||||
cell_size=CELL_SIZE,
|
raise(ValueError("Simulation configuration must be provided for SimulationEngine."))
|
||||||
initial_cells=350,
|
|
||||||
initial_food=FOOD_OBJECTS_COUNT,
|
|
||||||
food_spawning=FOOD_SPAWNING,
|
|
||||||
random_seed=RANDOM_SEED,
|
|
||||||
default_tps=DEFAULT_TPS
|
|
||||||
)
|
|
||||||
|
|
||||||
self.simulation_core = SimulationCore(sim_config, self.event_bus)
|
self.simulation_core = SimulationCore(sim_config, self.event_bus)
|
||||||
|
|
||||||
@ -147,7 +162,6 @@ class SimulationEngine:
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Run the interactive simulation engine."""
|
"""Run the interactive simulation engine."""
|
||||||
print(f"World buffer: {self.simulation_core.world.current_buffer}")
|
|
||||||
self.simulation_core.start()
|
self.simulation_core.start()
|
||||||
|
|
||||||
while self.running:
|
while self.running:
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import time
|
import time
|
||||||
import signal
|
import signal
|
||||||
import sys
|
|
||||||
from typing import Dict, Any, Optional, List
|
from typing import Dict, Any, Optional, List
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ from pathlib import Path
|
|||||||
project_root = Path(__file__).parent.parent
|
project_root = Path(__file__).parent.parent
|
||||||
sys.path.insert(0, str(project_root))
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
from config import ConfigLoader, InteractiveConfig
|
from config import ConfigLoader
|
||||||
from core.simulation_engine import SimulationEngine
|
from core.simulation_engine import SimulationEngine
|
||||||
|
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ def main():
|
|||||||
# Run simulation
|
# Run simulation
|
||||||
try:
|
try:
|
||||||
print("Starting interactive simulation...")
|
print("Starting interactive simulation...")
|
||||||
engine = SimulationEngine()
|
engine = SimulationEngine(config)
|
||||||
engine.run()
|
engine.run()
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
|||||||
@ -8,6 +8,7 @@ dependencies = [
|
|||||||
"numpy>=2.3.0",
|
"numpy>=2.3.0",
|
||||||
"pandas>=2.3.3",
|
"pandas>=2.3.3",
|
||||||
"pre-commit>=4.2.0",
|
"pre-commit>=4.2.0",
|
||||||
|
"psutil>=7.0.0",
|
||||||
"pydantic>=2.11.5",
|
"pydantic>=2.11.5",
|
||||||
"pygame>=2.6.1",
|
"pygame>=2.6.1",
|
||||||
"pygame-gui>=0.6.14",
|
"pygame-gui>=0.6.14",
|
||||||
|
|||||||
2
uv.lock
generated
2
uv.lock
generated
@ -142,6 +142,7 @@ dependencies = [
|
|||||||
{ name = "numpy" },
|
{ name = "numpy" },
|
||||||
{ name = "pandas" },
|
{ name = "pandas" },
|
||||||
{ name = "pre-commit" },
|
{ name = "pre-commit" },
|
||||||
|
{ name = "psutil" },
|
||||||
{ name = "pydantic" },
|
{ name = "pydantic" },
|
||||||
{ name = "pygame" },
|
{ name = "pygame" },
|
||||||
{ name = "pygame-gui" },
|
{ name = "pygame-gui" },
|
||||||
@ -162,6 +163,7 @@ requires-dist = [
|
|||||||
{ name = "numpy", specifier = ">=2.3.0" },
|
{ name = "numpy", specifier = ">=2.3.0" },
|
||||||
{ name = "pandas", specifier = ">=2.3.3" },
|
{ name = "pandas", specifier = ">=2.3.3" },
|
||||||
{ name = "pre-commit", specifier = ">=4.2.0" },
|
{ name = "pre-commit", specifier = ">=4.2.0" },
|
||||||
|
{ name = "psutil", specifier = ">=7.0.0" },
|
||||||
{ name = "pydantic", specifier = ">=2.11.5" },
|
{ name = "pydantic", specifier = ">=2.11.5" },
|
||||||
{ name = "pygame", specifier = ">=2.6.1" },
|
{ name = "pygame", specifier = ">=2.6.1" },
|
||||||
{ name = "pygame-gui", specifier = ">=0.6.14" },
|
{ name = "pygame-gui", specifier = ">=0.6.14" },
|
||||||
|
|||||||
@ -2,17 +2,14 @@ import math
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
from config.constants import MAX_VELOCITY, MAX_ACCELERATION, MAX_ROTATIONAL_VELOCITY, MAX_ANGULAR_ACCELERATION
|
from config.constants import MAX_VELOCITY, MAX_ACCELERATION, MAX_ROTATIONAL_VELOCITY, MAX_ANGULAR_ACCELERATION
|
||||||
|
from typing import List, Any, Union, Optional
|
||||||
from world.base.brain import CellBrain
|
from world.base.brain import CellBrain
|
||||||
from world.behavioral import BehavioralModel
|
|
||||||
from world.world import Position, BaseEntity, Rotation
|
from world.world import Position, BaseEntity, Rotation
|
||||||
import pygame
|
import pygame
|
||||||
from typing import Optional, List, Any, Union
|
|
||||||
|
|
||||||
from world.utils import get_distance_between_objects
|
from world.utils import get_distance_between_objects
|
||||||
from world.physics import Physics
|
from world.physics import Physics
|
||||||
|
|
||||||
from math import atan2, degrees
|
|
||||||
|
|
||||||
|
|
||||||
class DebugRenderObject(BaseEntity):
|
class DebugRenderObject(BaseEntity):
|
||||||
"""
|
"""
|
||||||
@ -254,15 +251,45 @@ class DefaultCell(BaseEntity):
|
|||||||
"""
|
"""
|
||||||
Cell object
|
Cell object
|
||||||
"""
|
"""
|
||||||
def __init__(self, starting_position: Position, starting_rotation: Rotation) -> None:
|
def __init__(self, starting_position: Position, starting_rotation: Rotation, entity_config=None) -> None:
|
||||||
"""
|
"""
|
||||||
Initializes the cell.
|
Initializes the cell.
|
||||||
|
|
||||||
:param starting_position: The position of the object.
|
:param starting_position: The position of the object.
|
||||||
|
:param entity_config: Configuration for entity hyperparameters.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
super().__init__(starting_position, starting_rotation)
|
super().__init__(starting_position, starting_rotation)
|
||||||
self.drag_coefficient: float = 0.1
|
|
||||||
|
# Use entity config or defaults
|
||||||
|
if entity_config:
|
||||||
|
cell_config = entity_config.entity_types.get("default_cell", {})
|
||||||
|
self.drag_coefficient: float = cell_config.get("drag_coefficient", 0.02)
|
||||||
|
self.energy: int = cell_config.get("starting_energy", 1000)
|
||||||
|
self.max_visual_width: int = cell_config.get("max_visual_width", 10)
|
||||||
|
self.interaction_radius: int = cell_config.get("interaction_radius", 50)
|
||||||
|
self.reproduction_energy: int = cell_config.get("reproduction_energy", 1700)
|
||||||
|
self.food_energy_value: int = cell_config.get("food_energy_value", 140)
|
||||||
|
self.energy_cost_base: float = cell_config.get("energy_cost_base", 1.5)
|
||||||
|
self.neural_network_complexity_cost: float = cell_config.get("neural_network_complexity_cost", 0.08)
|
||||||
|
self.movement_cost: float = cell_config.get("movement_cost", 0.25)
|
||||||
|
self.reproduction_count: int = cell_config.get("reproduction_count", 2)
|
||||||
|
self.mutation_rate: float = cell_config.get("mutation_rate", 0.05)
|
||||||
|
self.offspring_offset_range: int = cell_config.get("offspring_offset_range", 10)
|
||||||
|
else:
|
||||||
|
# Fallback to hardcoded defaults
|
||||||
|
self.drag_coefficient: float = 0.02
|
||||||
|
self.energy: int = 1000
|
||||||
|
self.max_visual_width: int = 10
|
||||||
|
self.interaction_radius: int = 50
|
||||||
|
self.reproduction_energy: int = 1700
|
||||||
|
self.food_energy_value: int = 140
|
||||||
|
self.energy_cost_base: float = 1.5
|
||||||
|
self.neural_network_complexity_cost: float = 0.08
|
||||||
|
self.movement_cost: float = 0.25
|
||||||
|
self.reproduction_count: int = 2
|
||||||
|
self.mutation_rate: float = 0.05
|
||||||
|
self.offspring_offset_range: int = 10
|
||||||
|
|
||||||
self.velocity: tuple[int, int] = (0, 0)
|
self.velocity: tuple[int, int] = (0, 0)
|
||||||
self.acceleration: tuple[int, int] = (0, 0)
|
self.acceleration: tuple[int, int] = (0, 0)
|
||||||
@ -270,20 +297,17 @@ class DefaultCell(BaseEntity):
|
|||||||
self.rotational_velocity: int = 0
|
self.rotational_velocity: int = 0
|
||||||
self.angular_acceleration: int = 0
|
self.angular_acceleration: int = 0
|
||||||
|
|
||||||
self.energy: int = 1000
|
|
||||||
|
|
||||||
self.behavioral_model: CellBrain = CellBrain()
|
self.behavioral_model: CellBrain = CellBrain()
|
||||||
|
|
||||||
self.max_visual_width: int = 10
|
|
||||||
self.interaction_radius: int = 50
|
|
||||||
self.flags: dict[str, bool] = {
|
self.flags: dict[str, bool] = {
|
||||||
"death": False,
|
"death": False,
|
||||||
"can_interact": True,
|
"can_interact": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tick_count = 0
|
self.tick_count = 0
|
||||||
|
self.entity_config = entity_config
|
||||||
|
|
||||||
self.physics = Physics(0.02, 0.05)
|
self.physics = Physics(self.drag_coefficient, self.drag_coefficient*1.5)
|
||||||
|
|
||||||
|
|
||||||
def set_brain(self, behavioral_model: CellBrain) -> None:
|
def set_brain(self, behavioral_model: CellBrain) -> None:
|
||||||
@ -321,27 +345,28 @@ class DefaultCell(BaseEntity):
|
|||||||
if distance_to_food < self.max_visual_width and food_objects:
|
if distance_to_food < self.max_visual_width and food_objects:
|
||||||
# Use atomic consumption to prevent race conditions
|
# Use atomic consumption to prevent race conditions
|
||||||
if food_object.try_claim():
|
if food_object.try_claim():
|
||||||
self.energy += 140
|
self.energy += self.food_energy_value
|
||||||
food_object.flag_for_death()
|
food_object.flag_for_death()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
if self.energy >= 1700:
|
if self.energy >= self.reproduction_energy:
|
||||||
# too much energy, split
|
# too much energy, split
|
||||||
duplicate_x, duplicate_y = self.position.get_position()
|
offspring = []
|
||||||
duplicate_x += random.randint(-self.max_visual_width, self.max_visual_width)
|
|
||||||
duplicate_y += random.randint(-self.max_visual_width, self.max_visual_width)
|
|
||||||
|
|
||||||
duplicate_x_2, duplicate_y_2 = self.position.get_position()
|
for _ in range(self.reproduction_count):
|
||||||
duplicate_x_2 += random.randint(-self.max_visual_width, self.max_visual_width)
|
duplicate_x, duplicate_y = self.position.get_position()
|
||||||
duplicate_y_2 += random.randint(-self.max_visual_width, self.max_visual_width)
|
duplicate_x += random.randint(-self.offspring_offset_range, self.offspring_offset_range)
|
||||||
|
duplicate_y += random.randint(-self.offspring_offset_range, self.offspring_offset_range)
|
||||||
|
|
||||||
new_cell = DefaultCell(Position(x=int(duplicate_x), y=int(duplicate_y)), Rotation(angle=random.randint(0, 359)))
|
new_cell = DefaultCell(
|
||||||
new_cell.set_brain(self.behavioral_model.mutate(0.05))
|
Position(x=int(duplicate_x), y=int(duplicate_y)),
|
||||||
|
Rotation(angle=random.randint(0, 359)),
|
||||||
|
entity_config=getattr(self, 'entity_config', None)
|
||||||
|
)
|
||||||
|
new_cell.set_brain(self.behavioral_model.mutate(self.mutation_rate))
|
||||||
|
offspring.append(new_cell)
|
||||||
|
|
||||||
new_cell_2 = DefaultCell(Position(x=int(duplicate_x_2), y=int(duplicate_y_2)), Rotation(angle=random.randint(0, 359)))
|
return offspring
|
||||||
new_cell_2.set_brain(self.behavioral_model.mutate(0.05))
|
|
||||||
|
|
||||||
return [new_cell, new_cell_2]
|
|
||||||
|
|
||||||
input_data = {
|
input_data = {
|
||||||
"distance": distance_to_food,
|
"distance": distance_to_food,
|
||||||
@ -371,7 +396,7 @@ class DefaultCell(BaseEntity):
|
|||||||
|
|
||||||
movement_cost = abs(output_data["angular_acceleration"]) + abs(output_data["linear_acceleration"])
|
movement_cost = abs(output_data["angular_acceleration"]) + abs(output_data["linear_acceleration"])
|
||||||
|
|
||||||
self.energy -= (self.behavioral_model.neural_network.network_cost * 0.08) + 1.5 + (0.25 * movement_cost)
|
self.energy -= (self.behavioral_model.neural_network.network_cost * self.neural_network_complexity_cost) + self.energy_cost_base + (self.movement_cost * movement_cost)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import List, Dict, Tuple, Optional, Any, TypeVar, Union
|
from typing import List, Dict, Tuple, Optional, Any, TypeVar
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
T = TypeVar("T", bound="BaseEntity")
|
T = TypeVar("T", bound="BaseEntity")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user