"""Advanced Dynamic Complex Environments: Ecosystems, Moving Predators, Terrain Fields & Shifting Gates. Extends the native embodied World with rich ecological and physical complexity: 1. **Dynamic Moving Predators & Coordinated Packs**: Autonomous drones that patrol, track, and flank. 2. **Dynamic Vector Flow Fields (River Currents & Conveyors)**: Physical current displacement fields. 3. **Topographic Elevation Hill Fields**: Continuous gravity-gradient forces that accelerate/retard motion. 4. **Sentinel Searchlights & Acoustic Tripwires**: Stealth zones, rotating light cones, and sound barriers. 5. **Multi-Switch Sequential Logic & Oscillating Gates**: Timed and pressure-actuated barrier bulkheads. 6. **Frontier Tasks**: - `ecosystem`: Foraging amidst regenerating resource patches and stalking predators. - `predator_evasion`: High-speed evasion of dual pursuit drones. - `dynamic_arena`: Timing passage through oscillating barrier gates. - `puzzle_chamber`: Button unlock mechanics and gate traversal. - `apex_megasite`: Cross-river traversal against vector currents, elevation hills, and pack hunters. - `stealth_labyrinth`: Corridor navigation evading rotating searchlights and tripwires via shadow cloaks. - `kinetic_foundry`: Navigating opposing conveyor belts and placing cargo blocks on pressure pads. """ from __future__ import annotations import math from collections import deque from typing import Any, Dict, List, Optional, Tuple import numpy as np from . import sources from graftbrain.world import World as BaseWorld, TASKS as BASE_TASKS, COLORS, HALF, RANGE, FOV, N_RAYS COMPLEX_TASKS = [ "ecosystem", "predator_evasion", "dynamic_arena", "puzzle_chamber", "apex_megasite", "stealth_labyrinth", "kinetic_foundry", "quantum_bifurcation", "cybernetic_sanctuary", "continental_biosphere", "chrono_tidepool_citadel", ] ALL_TASKS = BASE_TASKS + COMPLEX_TASKS class ComplexWorld(BaseWorld): """Frontier virtual 3D environment with dynamic multi-agent ecology, vector fields, and shifting terrain physics.""" def __init__(self, seed: int = 0, curriculum: str = "auto"): self.complex_seed = seed self.rng_complex = np.random.default_rng(seed) self.arena_half: float = float(HALF) self.predators: List[Dict[str, Any]] = [] self.helper_drones: List[Dict[str, Any]] = [] self.terrain_zones: List[Dict[str, Any]] = [] self.dynamic_gates: List[Dict[str, Any]] = [] self.elevation_hills: List[Dict[str, Any]] = [] self.sentinels: List[Dict[str, Any]] = [] self.sound_tripwires: List[Dict[str, Any]] = [] self.switches: List[Dict[str, Any]] = [] self.wormholes: List[Dict[str, Any]] = [] self.weather_fronts: List[Dict[str, Any]] = [] self.wormhole_cooldown: int = 0 self.last_alarm_tripped: bool = False self.day_night_clock = 0.0 self.ambient_light = 1.0 self.food_respawn_timer = 0 self.base_walls: List[Tuple[float, float, float, float]] = [] super().__init__(seed=seed, curriculum=curriculum) def _border(self, h: Optional[float] = None): bound = float(h if h is not None else getattr(self, "arena_half", HALF)) return [(-bound, -bound, bound, -bound), (bound, -bound, bound, bound), (bound, bound, -bound, bound), (-bound, bound, -bound, -bound)] def reset(self, task: Optional[str] = None): """Initializes both standard baseline and advanced complex tasks.""" self.arena_half = float(HALF) self.predators.clear() self.helper_drones.clear() self.terrain_zones.clear() self.dynamic_gates.clear() self.elevation_hills.clear() self.sentinels.clear() self.sound_tripwires.clear() self.switches.clear() self.wormholes.clear() self.weather_fronts.clear() self.wormhole_cooldown = 0 self.last_alarm_tripped = False # Check if the requested task is one of our new frontier tasks chosen_task = task or self.curriculum if chosen_task == "auto": chosen_task = ALL_TASKS[self.episode % len(ALL_TASKS)] # Run base reset obs = super().reset(chosen_task if chosen_task in BASE_TASKS else "forage") self.task = chosen_task # Setup specialized frontier mechanics if self.task == "ecosystem": self._setup_ecosystem() elif self.task == "predator_evasion": self._setup_predator_evasion() elif self.task == "dynamic_arena": self._setup_dynamic_arena() elif self.task == "puzzle_chamber": self._setup_puzzle_chamber() elif self.task == "apex_megasite": self._setup_apex_megasite() elif self.task == "stealth_labyrinth": self._setup_stealth_labyrinth() elif self.task == "kinetic_foundry": self._setup_kinetic_foundry() elif self.task == "quantum_bifurcation": self._setup_quantum_bifurcation() elif self.task == "cybernetic_sanctuary": self._setup_cybernetic_sanctuary() elif self.task == "continental_biosphere": self._setup_continental_biosphere() elif self.task == "chrono_tidepool_citadel": self._setup_chrono_tidepool_citadel() self.base_walls = self.walls.copy() self.history.setdefault(self.task, deque(maxlen=50)) self._prev = self._progress() return self.observe() # ------------------------------------------------------------------ # Frontier Task Setups # ------------------------------------------------------------------ def _setup_ecosystem(self): """Food patches with regrowth, 1 stalking predator, and terrain zones.""" self.objects.clear() self.walls = self._border() # Terrain zones self.terrain_zones = [ {"kind": "ice", "x": -2.5, "y": 0.0, "r": 1.6, "friction": 0.25, "color": "cyan"}, {"kind": "sand", "x": 2.5, "y": 0.0, "r": 1.6, "friction": 2.40, "color": "yellow"}, {"kind": "mud", "x": 0.0, "y": -2.5, "r": 1.4, "friction": 1.80, "color": "grey"}, ] # Regenerating food objects for _ in range(6): spot = self._free_spot(avoid=[(o['x'], o['y']) for o in self.objects]) self._obj("food", spot[0], spot[1], "green", r=0.25, movable=False) # Autonomous moving predator self.predators.append({ "id": 100, "x": 3.0, "y": 3.0, "th": float(self.rng_complex.uniform(0, math.pi * 2)), "speed": 0.12, "kind": "stalker", "r": 0.40, "color": "red", "alerted": False, }) def _setup_predator_evasion(self): """Intense evasion: 2 agile predator drones pursuing the agent while agent collects power orbs.""" self.objects.clear() self.walls = self._border() # Central shelter obstacle self.walls.extend([ (-1.2, -1.2, 1.2, -1.2), (1.2, -1.2, 1.2, 1.2), (1.2, 1.2, -1.2, 1.2), (-1.2, 1.2, -1.2, -1.2), ]) # Survival power orbs for _ in range(4): spot = self._free_spot(avoid=[(o['x'], o['y']) for o in self.objects]) self._obj("food", spot[0], spot[1], "gold", r=0.28, movable=False) # 2 Fast pursuit predators self.predators.append({ "id": 101, "x": -3.5, "y": 3.5, "th": 0.0, "speed": 0.16, "kind": "pursuer", "r": 0.38, "color": "red", "alerted": False, }) self.predators.append({ "id": 102, "x": 3.5, "y": -3.5, "th": math.pi, "speed": 0.14, "kind": "pursuer", "r": 0.38, "color": "purple", "alerted": False, }) def _setup_dynamic_arena(self): """Dynamic sliding gates and shifting corridors.""" self.objects.clear() self.walls = self._border() # Dynamic gates that oscillate self.dynamic_gates = [ {"id": "gate1", "x1": 0.0, "y1": -4.0, "x2": 0.0, "y2": -1.0, "open": False, "timer": 0}, {"id": "gate2", "x1": 0.0, "y1": 1.0, "x2": 0.0, "y2": 4.0, "open": True, "timer": 20}, ] # Target reward in far room self._obj("target", 3.5, 0.0, "green", r=0.35, movable=False) self._obj("food", -3.5, 0.0, "yellow", r=0.25, movable=False) def _setup_puzzle_chamber(self): """Button unlock puzzle: Press yellow button to open locked gate to gold goal.""" self.objects.clear() self.walls = self._border() # Dividing wall with locked gate self.walls.extend([ (0.0, -5.0, 0.0, -0.8), (0.0, 0.8, 0.0, 5.0), ]) self.dynamic_gates = [ {"id": "puzzle_gate", "x1": 0.0, "y1": -0.8, "x2": 0.0, "y2": 0.8, "open": False, "locked": True} ] # Button on left side self._obj("button", -2.5, 2.5, "yellow", r=0.35, shape="button", movable=False, solid=False, pressed=False) # Goal on right side self._obj("target", 3.0, 0.0, "gold", r=0.40, movable=False) def _setup_apex_megasite(self): """Apex frontier mega-environment: vector river current, 2 elevation hills, coordinated pack predators, and locked apex core.""" self.objects.clear() self.walls = self._border() # Central river vector current running north-to-south self.terrain_zones = [ {"kind": "river", "x": 0.0, "y": 0.0, "r": 2.2, "friction": 1.10, "vx": 0.0, "vy": -0.15, "color": "blue"}, {"kind": "sand", "x": -2.8, "y": -2.5, "r": 1.5, "friction": 2.20, "color": "yellow"}, {"kind": "ice", "x": 2.8, "y": 2.5, "r": 1.5, "friction": 0.30, "color": "cyan"}, ] # Topographic elevation hills self.elevation_hills = [ {"x": -2.6, "y": 2.0, "height": 1.8, "sigma": 1.4}, # West Plateau {"x": 2.6, "y": -2.0, "height": -1.5, "sigma": 1.3}, # East Basin ] # Coordinated predator pack (Leader + Flanker) self.predators.append({ "id": 201, "x": -3.2, "y": -3.2, "th": float(self.rng_complex.uniform(0, math.pi * 2)), "speed": 0.13, "kind": "pack_leader", "r": 0.38, "color": "red", "alerted": False, }) self.predators.append({ "id": 202, "x": -2.2, "y": -3.6, "th": float(self.rng_complex.uniform(0, math.pi * 2)), "speed": 0.12, "kind": "pack_hunter", "r": 0.36, "color": "darkred", "alerted": False, }) # Barrier separating the apex sanctuary on the east self.walls.extend([ (2.2, -5.0, 2.2, -1.0), (2.2, 1.0, 2.2, 5.0), ]) self.dynamic_gates = [ {"id": "apex_gate", "x1": 2.2, "y1": -1.0, "x2": 2.2, "y2": 1.0, "open": False, "locked": True} ] # Puzzle switch on the west plateau self._obj("button", -3.2, 2.6, "yellow", r=0.35, shape="button", movable=False, solid=False, pressed=False) # Apex Energy Core inside sanctuary self._obj("target", 3.8, 0.0, "gold", r=0.45, movable=False) # Regenerating forage crystals for _ in range(4): spot = self._free_spot(avoid=[(o['x'], o['y']) for o in self.objects]) self._obj("food", spot[0], spot[1], "green", r=0.25, movable=False) def _setup_stealth_labyrinth(self): """Stealth labyrinth: rotating sentinel searchlights, acoustic sound tripwires, cloaking shadow zones.""" self.objects.clear() self.walls = self._border() # Labyrinth dividing corridor walls self.walls.extend([ (-2.2, -4.5, -2.2, 0.8), (2.2, -0.8, 2.2, 4.5), (-4.5, 0.0, -1.2, 0.0), (1.2, 0.0, 4.5, 0.0), ]) # Cloaking shadow zones (prevent sentinel detection) self.terrain_zones = [ {"kind": "shadow", "x": -1.2, "y": -2.0, "r": 1.3, "friction": 1.0, "color": "purple"}, {"kind": "shadow", "x": 1.2, "y": 2.0, "r": 1.3, "friction": 1.0, "color": "purple"}, ] # Rotating sentinel searchlights self.sentinels = [ {"id": 301, "x": 0.0, "y": 2.2, "angle": 0.0, "angular_vel": 0.045, "range": 3.0, "cone_half_angle": 0.42, "alerted": False, "color": "orange"}, {"id": 302, "x": 0.0, "y": -2.2, "angle": math.pi, "angular_vel": -0.045, "range": 3.0, "cone_half_angle": 0.42, "alerted": False, "color": "orange"}, ] # Acoustic sound tripwire across central crossing self.sound_tripwires = [ {"id": "trip1", "x1": -1.0, "y1": 0.0, "x2": 1.0, "y2": 0.0, "max_safe_speed": 0.28} ] # Extraction beacon self._obj("target", 3.8, -3.8, "cyan", r=0.42, movable=False) # Stealth decoy orbs self._obj("food", -3.6, 3.6, "gold", r=0.26, movable=False) def _setup_kinetic_foundry(self): """Kinetic foundry: opposing directional conveyor belts, movable cargo box, and pressure plate reactor unlock.""" self.objects.clear() self.walls = self._border() # Opposing conveyor belts self.terrain_zones = [ {"kind": "conveyor", "x": -2.2, "y": 0.0, "r": 1.7, "friction": 0.9, "vx": 0.16, "vy": 0.0, "color": "orange"}, {"kind": "conveyor", "x": 2.2, "y": 0.0, "r": 1.7, "friction": 0.9, "vx": -0.16, "vy": 0.0, "color": "orange"}, {"kind": "conveyor", "x": 0.0, "y": -2.4, "r": 1.5, "friction": 0.9, "vx": 0.0, "vy": 0.16, "color": "orange"}, ] # Industrial blast barrier self.walls.extend([ (-5.0, 2.0, -1.2, 2.0), (1.2, 2.0, 5.0, 2.0), ]) self.dynamic_gates = [ {"id": "blast_door", "x1": -1.2, "y1": 2.0, "x2": 1.2, "y2": 2.0, "open": False, "locked": True} ] # Heavy cargo box self._obj("box", -2.2, 0.0, "grey", r=0.45, movable=True, solid=True) # Pressure sensor pad self._obj("pad", 2.2, 0.0, "yellow", r=0.60, shape="pad", movable=False, solid=False) # Foundry reactor core target self._obj("target", 0.0, 3.8, "purple", r=0.45, movable=False) def _setup_quantum_bifurcation(self): """Quantum bifurcation: dual phase-shifting bridge gates over a cross-current, entangled cue switch, and decoy vault.""" self.objects.clear() self.walls = self._border() # Bifurcating corridor walls self.walls.extend([ (-1.0, -5.0, -1.0, -1.6), (-1.0, 1.6, -1.0, 5.0), (1.6, -1.2, 5.0, -1.2), (1.6, 1.2, 5.0, 1.2), ]) # River current + ice slip zone + shadow cloak pocket self.terrain_zones = [ {"kind": "river", "x": 0.2, "y": 0.0, "r": 1.9, "friction": 1.05, "vx": 0.0, "vy": 0.14, "color": "blue"}, {"kind": "ice", "x": -2.8, "y": 0.0, "r": 1.4, "friction": 0.28, "color": "cyan"}, {"kind": "shadow", "x": 2.4, "y": 0.0, "r": 1.2, "friction": 1.0, "color": "purple"}, ] # Elevation basin & plateau self.elevation_hills = [ {"x": -2.5, "y": -2.5, "height": 1.4, "sigma": 1.3}, {"x": 2.5, "y": 2.8, "height": -1.3, "sigma": 1.3}, ] # Dual phase-shifting gates (one locked by entanglement button, one oscillating) self.dynamic_gates = [ {"id": "phase_bridge_north", "x1": -1.0, "y1": 0.0, "x2": -1.0, "y2": 1.6, "open": True, "timer": 10}, {"id": "phase_bridge_south", "x1": -1.0, "y1": -1.6, "x2": -1.0, "y2": 0.0, "open": False, "locked": True}, ] # Rotating sentinel guarding the bifurcation nexus self.sentinels = [ {"id": 401, "x": 1.4, "y": 0.0, "angle": 0.0, "angular_vel": 0.05, "range": 2.6, "cone_half_angle": 0.40, "alerted": False, "color": "orange"} ] # Entanglement calibration switch & quantum target core self._obj("button", -3.2, -2.5, "yellow", r=0.35, shape="button", movable=False, solid=False, pressed=False) self._obj("target", 3.8, 0.0, "cyan", r=0.44, movable=False) self._obj("food", -3.0, 2.5, "gold", r=0.28, movable=False) self._obj("food", 0.3, -2.8, "green", r=0.25, movable=False) def _setup_cybernetic_sanctuary(self): """Cybernetic sanctuary: autonomous cooperative helper drone with protective shield field, bio-reactor valves, and pack hunters.""" self.objects.clear() self.walls = self._border() # Sanctuary inner ring walls self.walls.extend([ (1.8, -5.0, 1.8, -1.1), (1.8, 1.1, 1.8, 5.0), ]) self.dynamic_gates = [ {"id": "sanctuary_bulkhead", "x1": 1.8, "y1": -1.1, "x2": 1.8, "y2": 1.1, "open": False, "locked": True} ] self.terrain_zones = [ {"kind": "conveyor", "x": -1.8, "y": 1.8, "r": 1.5, "friction": 0.9, "vx": 0.14, "vy": -0.06, "color": "orange"}, {"kind": "shadow", "x": -0.5, "y": -2.2, "r": 1.4, "friction": 1.0, "color": "purple"}, ] # Cooperative Helper Drone (orbits and projects a stabilizing shield aura) self.helper_drones = [ { "id": 501, "x": 1.0, "y": 0.0, "th": 0.0, "orbit_angle": 0.0, "orbit_center": [-0.6, 0.0], "orbit_radius": 1.6, "shield_radius": 1.6, "r": 0.32, "kind": "guardian_drone", "color": "cyan", "active": True, } ] # Perimeter stalker drone self.predators.append({ "id": 205, "x": -3.2, "y": -3.0, "th": 0.5, "speed": 0.12, "kind": "pack_leader", "r": 0.36, "color": "red", "alerted": False, }) # Bio-reactor valve button & sanctuary core target self._obj("button", -2.8, 2.4, "yellow", r=0.36, shape="button", movable=False, solid=False, pressed=False) self._obj("target", 3.6, 0.0, "gold", r=0.45, movable=False) for _ in range(3): spot = self._free_spot(avoid=[(o['x'], o['y']) for o in self.objects]) self._obj("food", spot[0], spot[1], "green", r=0.25, movable=False) def _setup_continental_biosphere(self): """Mega-scale 17x17 (arena_half=8.5) multi-biome continental ecosystem with wormhole relays, weather storms, 3 predator packs, and 2 guardian drones.""" self.arena_half = 8.5 self.max_t = 700 self.objects.clear() self.walls = self._border(self.arena_half) self.a.update(x=-6.5, y=-6.0, th=0.4) # Continental mountain ridge barriers with central canyon gates self.walls.extend([ (-1.5, -8.5, -1.5, -2.5), (-1.5, 2.5, -1.5, 8.5), (3.5, -8.5, 3.5, -1.8), (3.5, 1.8, 3.5, 8.5), ]) self.dynamic_gates = [ {"id": "canyon_west_gate", "x1": -1.5, "y1": -2.5, "x2": -1.5, "y2": 2.5, "open": True, "timer": 10}, {"id": "citadel_east_gate", "x1": 3.5, "y1": -1.8, "x2": 3.5, "y2": 1.8, "open": False, "locked": True}, ] # 5 Continental Biomes self.terrain_zones = [ {"kind": "ice", "x": -5.2, "y": 4.8, "r": 2.6, "friction": 0.25, "color": "cyan"}, {"kind": "sand", "x": -4.8, "y": -4.5, "r": 2.5, "friction": 2.35, "color": "yellow"}, {"kind": "river", "x": 1.0, "y": 0.0, "r": 2.8, "friction": 1.10, "vx": 0.0, "vy": -0.16, "color": "blue"}, {"kind": "mud", "x": 1.2, "y": -5.5, "r": 2.2, "friction": 1.85, "color": "grey"}, {"kind": "shadow", "x": 1.0, "y": 5.2, "r": 2.2, "friction": 1.0, "color": "purple"}, ] # 3 Topographic Mountain / Basin Elevation Hills self.elevation_hills = [ {"x": -5.0, "y": 0.5, "height": 2.2, "sigma": 2.0}, {"x": 1.0, "y": 3.5, "height": -1.8, "sigma": 1.8}, {"x": 6.0, "y": -4.0, "height": 2.0, "sigma": 1.9}, ] # Paired Quantum Wormhole Relay (transports agent from (-6.0, 6.0) <-> (2.2, -6.0)) self.wormholes = [ {"id": "wormhole_alpha", "label": "ALPHA RELAY", "x": -6.0, "y": 6.0, "x1": -6.0, "y1": 6.0, "x2": 2.2, "y2": -6.0, "r": 0.75, "target_x": 2.2, "target_y": -6.0, "color": "#00e5ff"}, {"id": "wormhole_omega", "label": "OMEGA RELAY", "x": 2.2, "y": -6.0, "x1": 2.2, "y1": -6.0, "x2": -6.0, "y2": 6.0, "r": 0.75, "target_x": -6.0, "target_y": 6.0, "color": "#c084fc"}, ] # Dynamic Electromagnetic Weather Storm Fronts self.weather_fronts = [ {"id": "ion_storm_1", "kind": "ion_storm", "x": -2.0, "y": 0.0, "r": 2.4, "vx": 0.05, "vy": 0.04, "wind_x": -0.05, "wind_y": 0.04, "sensor_noise": 0.03}, {"id": "monsoon_squall_2", "kind": "monsoon_squall", "x": 4.2, "y": -2.5, "r": 2.1, "vx": -0.04, "vy": 0.05, "wind_x": 0.04, "wind_y": -0.03, "sensor_noise": 0.025}, ] # 2 Cooperative Guardian Drones self.helper_drones = [ { "id": 601, "x": -1.4, "y": 0.0, "th": 0.0, "orbit_angle": 0.0, "orbit_center": [-3.4, 0.0], "orbit_radius": 2.0, "shield_radius": 1.9, "r": 0.34, "kind": "guardian_drone", "color": "cyan", "active": True, }, { "id": 602, "x": 3.0, "y": 0.0, "th": math.pi, "orbit_angle": math.pi, "orbit_center": [1.0, 0.0], "orbit_radius": 2.0, "shield_radius": 1.9, "r": 0.34, "kind": "guardian_drone", "color": "cyan", "active": True, }, ] # 3 Coordinated Predator Drones self.predators.extend([ {"id": 301, "x": -4.5, "y": 3.5, "th": 0.0, "speed": 0.14, "kind": "pack_leader", "r": 0.38, "color": "red", "alerted": False}, {"id": 302, "x": 0.8, "y": -3.8, "th": 1.2, "speed": 0.15, "kind": "pack_hunter", "r": 0.38, "color": "purple", "alerted": False}, {"id": 303, "x": 5.5, "y": 4.2, "th": -1.0, "speed": 0.13, "kind": "stalker", "r": 0.38, "color": "red", "alerted": False}, ]) self._obj("button", 1.2, 5.2, "yellow", r=0.40, shape="button", movable=False, solid=False, pressed=False) self._obj("target", 6.8, 0.0, "gold", r=0.50, movable=False) for fx, fy in [(-6.2, -1.5), (-3.0, 5.5), (0.0, -6.2), (2.2, 2.8), (5.8, -5.5), (6.0, 5.0)]: self._obj("food", fx, fy, "green", r=0.28, movable=False) def _setup_chrono_tidepool_citadel(self): """Poseidon Tidepool v2 inspired 15x15 (arena_half=7.5) observation-aliased tidal arena with periodic surge waves and cue beacons.""" self.arena_half = 7.5 self.max_t = 650 self.objects.clear() self.walls = self._border(self.arena_half) self.a.update(x=-5.8, y=0.0, th=0.0) self.cue = np.array([1.0, 0.0, 0.5, -0.5], dtype=np.float32) # Citadel inner sanctum walls self.walls.extend([ (2.8, -7.5, 2.8, -1.4), (2.8, 1.4, 2.8, 7.5), ]) self.dynamic_gates = [ {"id": "tidepool_sluice", "x1": 2.8, "y1": -1.4, "x2": 2.8, "y2": 1.4, "open": False, "locked": True}, ] # Tidal surge vector channels & stealth kelp shadow zones self.terrain_zones = [ {"kind": "river", "x": -1.5, "y": 2.8, "r": 2.4, "friction": 1.15, "vx": -0.14, "vy": 0.08, "color": "blue"}, {"kind": "river", "x": -1.5, "y": -2.8, "r": 2.4, "friction": 1.15, "vx": 0.14, "vy": -0.08, "color": "cyan"}, {"kind": "shadow", "x": -4.0, "y": 0.0, "r": 1.8, "friction": 1.0, "color": "purple"}, {"kind": "sand", "x": 1.0, "y": 0.0, "r": 2.0, "friction": 2.10, "color": "yellow"}, ] self.wormholes = [ {"id": "tide_relay_north", "label": "TIDE RELAY N", "x": -5.0, "y": 5.2, "x1": -5.0, "y1": 5.2, "x2": 1.2, "y2": -4.8, "r": 0.70, "target_x": 1.2, "target_y": -4.8, "color": "#00e5ff"}, {"id": "tide_relay_south", "label": "TIDE RELAY S", "x": 1.2, "y": -4.8, "x1": 1.2, "y1": -4.8, "x2": -5.0, "y2": 5.2, "r": 0.70, "target_x": -5.0, "target_y": 5.2, "color": "#c084fc"}, ] self.weather_fronts = [ {"id": "tidal_squall", "kind": "tidal_squall", "x": 0.0, "y": 0.0, "r": 2.6, "vx": 0.04, "vy": -0.05, "wind_x": -0.06, "wind_y": 0.03, "sensor_noise": 0.04} ] self.sentinels = [ {"id": 410, "x": 0.5, "y": 3.5, "angle": 0.0, "angular_vel": 0.045, "range": 3.8, "cone_half_angle": 0.38, "color": "yellow", "alerted": False}, {"id": 411, "x": 0.5, "y": -3.5, "angle": math.pi, "angular_vel": -0.045, "range": 3.8, "cone_half_angle": 0.38, "color": "yellow", "alerted": False}, ] self.helper_drones = [ { "id": 610, "x": 0.3, "y": 0.0, "th": 0.0, "orbit_angle": 0.0, "orbit_center": [-1.5, 0.0], "orbit_radius": 1.8, "shield_radius": 1.75, "r": 0.32, "kind": "guardian_drone", "color": "cyan", "active": True, } ] self.predators.append({ "id": 310, "x": 4.8, "y": 3.2, "th": -1.5, "speed": 0.14, "kind": "pursuer", "r": 0.38, "color": "red", "alerted": False }) self._obj("button", -1.2, -4.8, "yellow", r=0.38, shape="button", movable=False, solid=False, pressed=False) self._obj("target", 5.8, 0.0, "gold", r=0.48, movable=False) for fx, fy in [(-4.5, -3.5), (-2.0, 4.8), (1.5, 4.2), (5.0, -3.5)]: self._obj("food", fx, fy, "green", r=0.26, movable=False) # ------------------------------------------------------------------ # Step Physics & Environmental Updates # ------------------------------------------------------------------ def step(self, action: np.ndarray): from .actions import DRIVE, validate_action action = validate_action(action) # 1. Terrain zone physics (modulate thrust/turn and compute flow displacement) current_friction = 1.0 in_friction_zone = False flow_dx, flow_dy = 0.0, 0.0 ax, ay = self.a["x"], self.a["y"] for zone in self.terrain_zones: dist = math.hypot(ax - zone["x"], ay - zone["y"]) if dist < zone["r"]: current_friction = zone.get("friction", 1.0) flow_dx += zone.get("vx", 0.0) flow_dy += zone.get("vy", 0.0) in_friction_zone = True # Adjust effective action under terrain friction eff_action = action.copy() eff_action[DRIVE] = np.clip(eff_action[DRIVE] / current_friction, -1, 1) # 2. Step base environment _, reward, done, info = super().step(eff_action) base_reward = reward ax, ay = self.a['x'], self.a['y'] info["in_friction_zone"] = in_friction_zone info["terrain_friction"] = current_friction # 3. Vector Flow Displacement & Object Current Physics arena_bound = float(getattr(self, "arena_half", HALF)) if flow_dx != 0.0 or flow_dy != 0.0: h = arena_bound - 0.35 self.a["x"] = float(np.clip(self.a["x"] + flow_dx, -h, h)) self.a["y"] = float(np.clip(self.a["y"] + flow_dy, -h, h)) ax, ay = self.a["x"], self.a["y"] # Move movable objects caught in vector flow zones for obj in self.objects: if obj.get("movable") and not obj.get("held"): for zone in self.terrain_zones: if math.hypot(obj["x"] - zone["x"], obj["y"] - zone["y"]) < zone["r"]: obj["x"] = float(np.clip(obj["x"] + zone.get("vx", 0.0), -arena_bound + 0.35, arena_bound - 0.35)) obj["y"] = float(np.clip(obj["y"] + zone.get("vy", 0.0), -arena_bound + 0.35, arena_bound - 0.35)) # 4. Topographic Elevation Gravity Gradient if self.elevation_hills: gx, gy = 0.0, 0.0 for hill in self.elevation_hills: hx, hy = hill["x"], hill["y"] H, sigma = hill["height"], hill["sigma"] dx = ax - hx dy = ay - hy d2 = dx * dx + dy * dy val = H * math.exp(-d2 / (2.0 * sigma * sigma)) gx += - (dx / (sigma * sigma)) * val gy += - (dy / (sigma * sigma)) * val # Gravitational drift acceleration applied to agent h = arena_bound - 0.35 self.a["x"] = float(np.clip(self.a["x"] - 0.04 * gx, -h, h)) self.a["y"] = float(np.clip(self.a["y"] - 0.04 * gy, -h, h)) ax, ay = self.a["x"], self.a["y"] info["elevation_gradient"] = [round(float(gx), 4), round(float(gy), 4)] # 5. Dynamic Gates & Puzzle Locks for gate in self.dynamic_gates: if gate.get("locked"): # Check if puzzle button was pressed or box is placed on pad button_pressed = any(obj.get("kind") == "button" and obj.get("pressed") for obj in self.objects) box_on_pad = False box = next((o for o in self.objects if o.get("kind") == "box"), None) pad = next((o for o in self.objects if o.get("kind") == "pad"), None) if box and pad and math.hypot(box["x"] - pad["x"], box["y"] - pad["y"]) < 0.65: box_on_pad = True if button_pressed or box_on_pad: gate["open"] = True else: gate["timer"] = (gate.get("timer", 0) + 1) % 50 gate["open"] = gate["timer"] < 25 # Rebuild walls including currently closed gates if self.dynamic_gates: active_walls = self.base_walls.copy() for gate in self.dynamic_gates: if not gate.get("open", False): active_walls.append((gate["x1"], gate["y1"], gate["x2"], gate["y2"])) self.walls = active_walls # 6. Coordinated Predator Pack Dynamics min_hazard_dist = 10.0 pack_alerted = any(p.get("alerted", False) for p in self.predators) # Check if any predator spots agent for pred in self.predators: p_dist = math.hypot(ax - pred["x"], ay - pred["y"]) if p_dist < 3.5: pred["alerted"] = True pack_alerted = True for pred in self.predators: if pack_alerted: pred["alerted"] = True p_dx = ax - pred["x"] p_dy = ay - pred["y"] dist_to_agent = math.hypot(p_dx, p_dy) if pred["kind"] == "pursuer" or (pred.get("alerted") and pred["kind"] in ("pack_leader", "stalker")): # Direct chase steering desired_th = math.atan2(p_dy, p_dx) pred["th"] += 0.14 * math.sin(desired_th - pred["th"]) elif pred.get("alerted") and pred["kind"] == "pack_hunter": # Flanking pursuit: steer toward predicted lead position lead_x = ax + math.cos(self.a["th"]) * self.a["v"] * 2.0 lead_y = ay + math.sin(self.a["th"]) * self.a["v"] * 2.0 desired_th = math.atan2(lead_y - pred["y"], lead_x - pred["x"]) pred["th"] += 0.16 * math.sin(desired_th - pred["th"]) else: # Patrol bounce pred["th"] += float(self.rng_complex.normal(0.0, 0.08)) # Move predator pred_speed = pred["speed"] * (1.3 if pred.get("alerted") else 1.0) pred["x"] += math.cos(pred["th"]) * pred_speed pred["y"] += math.sin(pred["th"]) * pred_speed # Arena boundary bounce h = arena_bound - 0.5 if pred["x"] < -h or pred["x"] > h: pred["th"] = math.pi - pred["th"] pred["x"] = float(np.clip(pred["x"], -h, h)) if pred["y"] < -h or pred["y"] > h: pred["th"] = -pred["th"] pred["y"] = float(np.clip(pred["y"], -h, h)) # Collision with agent dist_to_agent = math.hypot(ax - pred['x'], ay - pred['y']) min_hazard_dist = min(min_hazard_dist, dist_to_agent) if dist_to_agent < (pred["r"] + 0.35): reward -= 0.45 info["predator_impact"] = True info["min_hazard_dist"] = min_hazard_dist # 7. Rotating Sentinel Searchlights & Stealth Cloak Mechanics alarm_tripped = False in_shadow = any( tz.get("kind") == "shadow" and math.hypot(ax - tz["x"], ay - tz["y"]) < tz["r"] for tz in self.terrain_zones ) info["in_shadow"] = in_shadow for sentinel in self.sentinels: sentinel["angle"] = (sentinel["angle"] + sentinel.get("angular_vel", 0.04)) % (math.pi * 2) if not in_shadow: s_dx = ax - sentinel["x"] s_dy = ay - sentinel["y"] s_dist = math.hypot(s_dx, s_dy) if s_dist < sentinel["range"]: rel_angle = (math.atan2(s_dy, s_dx) - sentinel["angle"] + math.pi) % (math.pi * 2) - math.pi if abs(rel_angle) < sentinel["cone_half_angle"]: sentinel["alerted"] = True alarm_tripped = True reward -= 0.30 sentinel["color"] = "red" # 8. Acoustic Sound Tripwires agent_speed = abs(self.a["v"]) for trip in self.sound_tripwires: # Check segment proximity t_x1, t_y1, t_x2, t_y2 = trip["x1"], trip["y1"], trip["x2"], trip["y2"] seg_dist = abs((t_y2 - t_y1) * ax - (t_x2 - t_x1) * ay + t_x2 * t_y1 - t_y2 * t_x1) / max(1e-5, math.hypot(t_y2 - t_y1, t_x2 - t_x1)) if seg_dist < 0.4 and min(t_x1, t_x2) - 0.2 <= ax <= max(t_x1, t_x2) + 0.2 and min(t_y1, t_y2) - 0.2 <= ay <= max(t_y1, t_y2) + 0.2: if agent_speed > trip.get("max_safe_speed", 0.30): alarm_tripped = True reward -= 0.25 self.last_alarm_tripped = alarm_tripped info["alarm_tripped"] = alarm_tripped # 9. Ecological Food Respawn self.food_respawn_timer += 1 if self.task in ("ecosystem", "apex_megasite") and self.food_respawn_timer % 40 == 0: current_food = sum(1 for o in self.objects if o.get("kind") == "food" and o.get("visible", True)) max_food = 6 if self.task == "ecosystem" else 4 if current_food < max_food: spot = self._free_spot(avoid=[(o['x'], o['y']) for o in self.objects]) self._obj("food", spot[0], spot[1], "green", r=0.25, movable=False) # 10. Ambient Illumination Cycle & Cooperative Helper Drones self.day_night_clock += 0.015 self.ambient_light = float(0.65 + 0.35 * math.sin(self.day_night_clock)) info["ambient_light"] = self.ambient_light helper_shield_active = False for drone in self.helper_drones: drone["orbit_angle"] = float(drone.get("orbit_angle", 0.0) + 0.065) % (math.pi * 2) cx, cy = drone.get("orbit_center", [0.0, 0.0]) rad = float(drone.get("orbit_radius", 1.5)) nx = float(cx + math.cos(drone["orbit_angle"]) * rad) ny = float(cy + math.sin(drone["orbit_angle"]) * rad) drone["th"] = float(math.atan2(ny - drone["y"], nx - drone["x"])) drone["x"], drone["y"] = nx, ny if math.hypot(ax - nx, ay - ny) <= float(drone.get("shield_radius", 1.6)): helper_shield_active = True reward += 0.04 info["min_hazard_dist"] = max(float(info.get("min_hazard_dist", 10.0)), 6.0) info["helper_shield_active"] = helper_shield_active # 10b. Wormhole Teleportation Relays & Weather Storm Fronts if getattr(self, "wormhole_cooldown", 0) > 0: self.wormhole_cooldown -= 1 wormhole_teleported = False for wh in getattr(self, "wormholes", []): if self.wormhole_cooldown == 0 and math.hypot(ax - wh["x"], ay - wh["y"]) <= float(wh.get("r", 0.75)): self.a["x"] = float(wh["target_x"]) self.a["y"] = float(wh["target_y"]) ax, ay = self.a["x"], self.a["y"] self.wormhole_cooldown = 18 wormhole_teleported = True reward += 0.15 break info["wormhole_teleported"] = wormhole_teleported in_weather_storm = False for storm in getattr(self, "weather_fronts", []): storm["x"] = float(storm["x"] + storm.get("vx", 0.03)) storm["y"] = float(storm["y"] + storm.get("vy", 0.02)) sb = arena_bound - 1.2 if abs(storm["x"]) > sb: storm["vx"] = -storm.get("vx", 0.03) storm["x"] = float(np.clip(storm["x"], -sb, sb)) if abs(storm["y"]) > sb: storm["vy"] = -storm.get("vy", 0.02) storm["y"] = float(np.clip(storm["y"], -sb, sb)) if math.hypot(ax - storm["x"], ay - storm["y"]) <= float(storm.get("r", 2.4)): in_weather_storm = True h = arena_bound - 0.35 self.a["x"] = float(np.clip(self.a["x"] + storm.get("wind_x", 0.0), -h, h)) self.a["y"] = float(np.clip(self.a["y"] + storm.get("wind_y", 0.0), -h, h)) ax, ay = self.a["x"], self.a["y"] info["in_weather_storm"] = in_weather_storm # 11. Complex Task Completion and Terminal Goal Rewards target_obj = next((o for o in self.objects if o.get("kind") == "target"), None) if target_obj is not None: dist_to_target = math.hypot(ax - target_obj["x"], ay - target_obj["y"]) if dist_to_target < (target_obj.get("r", 0.4) + 0.25): if self.task in ("puzzle_chamber", "cybernetic_sanctuary", "continental_biosphere", "chrono_tidepool_citadel"): btn = next((o for o in self.objects if o.get("kind") == "button"), None) if btn and btn.get("pressed"): done = True reward += 6.0 if self.task == "puzzle_chamber" else 9.0 info["outcome"] = "success" elif self.task in ("dynamic_arena", "apex_megasite", "stealth_labyrinth", "kinetic_foundry", "quantum_bifurcation"): done = True reward += 8.0 info["outcome"] = "success" # Update episode accounting self.ep_return += (reward - base_reward) self.last_reward = reward if done: info['ret'] = self.ep_return return self.observe(), reward, done, info def _progress(self) -> float: """Task potential progress function across both base and frontier tasks.""" t = self.task ax, ay = self.a["x"], self.a["y"] if t in ("ecosystem", "predator_evasion"): visible_food = [o for o in self.objects if o.get("kind") == "food" and o.get("visible", True)] if visible_food: min_f = min(math.hypot(ax - f["x"], ay - f["y"]) for f in visible_food) pot = -min_f else: pot = 0.0 if t == "predator_evasion" and self.predators: min_p = min(math.hypot(ax - p["x"], ay - p["y"]) for p in self.predators) pot += 0.25 * min_p return pot if t == "dynamic_arena": target = next((o for o in self.objects if o.get("kind") == "target"), None) return -math.hypot(ax - target["x"], ay - target["y"]) if target else 0.0 if t == "puzzle_chamber": btn = next((o for o in self.objects if o.get("kind") == "button"), None) target = next((o for o in self.objects if o.get("kind") == "target"), None) if btn and not btn.get("pressed"): return -math.hypot(ax - btn["x"], ay - btn["y"]) if target: return 2.0 - math.hypot(ax - target["x"], ay - target["y"]) return 0.0 if t == "apex_megasite": btn = next((o for o in self.objects if o.get("kind") == "button"), None) target = next((o for o in self.objects if o.get("kind") == "target"), None) if btn and not btn.get("pressed"): return -math.hypot(ax - btn["x"], ay - btn["y"]) if target: return 3.0 - math.hypot(ax - target["x"], ay - target["y"]) return 0.0 if t == "stealth_labyrinth": target = next((o for o in self.objects if o.get("kind") == "target"), None) alarm_pen = -1.0 if getattr(self, "last_alarm_tripped", False) else 0.0 return (-math.hypot(ax - target["x"], ay - target["y"]) + alarm_pen) if target else 0.0 if t == "kinetic_foundry": box = next((o for o in self.objects if o.get("kind") == "box"), None) pad = next((o for o in self.objects if o.get("kind") == "pad"), None) target = next((o for o in self.objects if o.get("kind") == "target"), None) if box and pad: box_pad_dist = math.hypot(box["x"] - pad["x"], box["y"] - pad["y"]) if box_pad_dist > 0.65: return -math.hypot(ax - box["x"], ay - box["y"]) - 1.5 * box_pad_dist if target: return 3.0 - math.hypot(ax - target["x"], ay - target["y"]) return 0.0 if t in ("quantum_bifurcation", "cybernetic_sanctuary", "continental_biosphere", "chrono_tidepool_citadel"): btn = next((o for o in self.objects if o.get("kind") == "button"), None) target = next((o for o in self.objects if o.get("kind") == "target"), None) if btn and not btn.get("pressed"): return -math.hypot(ax - btn["x"], ay - btn["y"]) if target: return 3.0 - math.hypot(ax - target["x"], ay - target["y"]) return 0.0 # Delegate base tasks to BaseWorld._progress return super()._progress() def observe(self): """Generates 155-dim sensory observation with ambient lighting modulation.""" a = self.a prop = [ (a["reach"] - 0.25) / 0.65, a["height"] / 0.75, a["grip"], float(a["held"] is not None), a["v"] / 1.4, a["w"] / 2.5, math.sin(a["th"]), math.cos(a["th"]), ] if self.task in BASE_TASKS: onehot = np.eye(len(BASE_TASKS))[BASE_TASKS.index(self.task)] else: idx = (BASE_TASKS.index("forage") + COMPLEX_TASKS.index(self.task)) % len(BASE_TASKS) onehot = np.eye(len(BASE_TASKS))[idx] ret = self.retina() if hasattr(self, "ambient_light") and self.ambient_light != 1.0: ret = ret * float(self.ambient_light) return np.concatenate([ret, prop, onehot, self.cue, [self.last_reward, self.t / self.max_t]]).astype(np.float32) def snapshot(self) -> Dict[str, Any]: """Extends snapshot with predators, terrain zones, vector fields, sentinels, and elevation hills.""" snap = super().snapshot() snap["predators"] = [ { "id": p["id"], "x": round(float(p["x"]), 3), "y": round(float(p["y"]), 3), "th": round(float(p["th"]), 3), "r": p["r"], "kind": p["kind"], "color": p["color"], "alerted": p.get("alerted", False), } for p in self.predators ] snap["terrain_zones"] = self.terrain_zones snap["dynamic_gates"] = self.dynamic_gates snap["elevation_hills"] = self.elevation_hills snap["sentinels"] = self.sentinels snap["sound_tripwires"] = self.sound_tripwires snap["helper_drones"] = [ { "id": d["id"], "x": round(float(d["x"]), 3), "y": round(float(d["y"]), 3), "th": round(float(d.get("th", 0.0)), 3), "r": d.get("r", 0.32), "shield_radius": d.get("shield_radius", 1.6), "kind": d.get("kind", "guardian_drone"), "color": d.get("color", "cyan"), } for d in self.helper_drones ] snap["ambient_light"] = round(self.ambient_light, 3) snap["alarm_tripped"] = self.last_alarm_tripped snap["half"] = round(float(getattr(self, "arena_half", HALF)), 3) snap["wormholes"] = [ { "id": wh["id"], "x": round(float(wh["x"]), 3), "y": round(float(wh["y"]), 3), "r": float(wh.get("r", 0.75)), "target_x": round(float(wh["target_x"]), 3), "target_y": round(float(wh["target_y"]), 3), "color": wh.get("color", "purple"), } for wh in getattr(self, "wormholes", []) ] snap["weather_fronts"] = [ { "id": wf["id"], "x": round(float(wf["x"]), 3), "y": round(float(wf["y"]), 3), "r": float(wf.get("r", 2.4)), "wind_x": round(float(wf.get("wind_x", 0.0)), 3), "wind_y": round(float(wf.get("wind_y", 0.0)), 3), } for wf in getattr(self, "weather_fronts", []) ] return snap