Spaces:
Runtime error
Runtime error
| """Deterministic autopilot for social (non-survival) worlds. | |
| The autopilot fills gaps: it produces one safe, goal-consistent primitive when | |
| an NPC has no usable directive (LLM error, unknown action, omitted NPC). It is | |
| a fallback, never a filter — it does not constrain what a planner may choose. | |
| """ | |
| from __future__ import annotations | |
| from world_simulator.domain import CitizenGoal, Npc, WorldState | |
| from world_simulator.simulation.connectors.base import NpcDirective | |
| from world_simulator.simulation.mechanics import ( | |
| ATTACK_RADIUS, | |
| distance_between, | |
| is_alive, | |
| walk_away_target, | |
| ) | |
| from world_simulator.simulation.perception import CitizenPerception, nearby_threat_npc | |
| def autopilot_directive( | |
| world: WorldState, | |
| npc: Npc, | |
| directive: NpcDirective, | |
| perception: CitizenPerception, | |
| goal: CitizenGoal | None, | |
| ) -> NpcDirective: | |
| target = target_from_directive_or_goal(world, npc, directive, goal, perception) | |
| if ( | |
| goal is not None | |
| and goal.goal_type in ("pursue_and_attack_target", "retaliate") | |
| and target is not None | |
| ): | |
| return strike_or_approach_target( | |
| npc, | |
| directive, | |
| target, | |
| memory="Autopilot pursued the hostile target.", | |
| ) | |
| if goal is not None and goal.goal_type in ("survive", "call_for_help", "help_or_defend"): | |
| if goal.goal_type == "call_for_help": | |
| return NpcDirective( | |
| npc_id=npc.id, | |
| action="speak", | |
| message="Help! I am in danger!", | |
| memory="Autopilot called for help.", | |
| communication_intent="help_request", | |
| intent="call_for_help", | |
| ) | |
| if target is not None: | |
| return flee_directive(world, npc, target, directive) | |
| return idle_directive( | |
| directive, | |
| memory="Autopilot held a defensive stance.", | |
| intent="defend", | |
| ) | |
| if ( | |
| goal is not None | |
| and goal.goal_type in ("respond_to_event", "investigate") | |
| and target is not None | |
| ): | |
| return move_toward_target_directive(npc, directive, target, intent="investigate") | |
| return idle_directive(directive, memory=None, intent="observe") | |
| def target_from_directive_or_goal( | |
| world: WorldState, | |
| npc: Npc, | |
| directive: NpcDirective, | |
| goal: CitizenGoal | None, | |
| perception: CitizenPerception, | |
| ) -> Npc | None: | |
| if directive.target_npc_id: | |
| target = _npc_by_id(world, directive.target_npc_id) | |
| if target is not None and target.id != npc.id and is_alive(target): | |
| return target | |
| if goal is not None and goal.target_npc_id: | |
| target = _npc_by_id(world, goal.target_npc_id) | |
| if target is not None and target.id != npc.id and is_alive(target): | |
| return target | |
| threat = nearby_threat_npc(world, perception) | |
| if threat is not None and threat.id != npc.id and is_alive(threat): | |
| return threat | |
| return None | |
| def strike_or_approach_target( | |
| npc: Npc, | |
| directive: NpcDirective, | |
| target: Npc, | |
| *, | |
| memory: str, | |
| ) -> NpcDirective: | |
| if distance_between(npc, target) <= ATTACK_RADIUS: | |
| return NpcDirective( | |
| npc_id=npc.id, | |
| action="attack", | |
| target_npc_id=target.id, | |
| message=directive.message, | |
| memory=memory, | |
| intent="hostile_attack", | |
| confidence=directive.confidence, | |
| ) | |
| return move_toward_target_directive( | |
| npc, | |
| directive, | |
| target, | |
| intent="approach_target_for_attack", | |
| memory=memory, | |
| ) | |
| def move_toward_target_directive( | |
| npc: Npc, | |
| directive: NpcDirective, | |
| target: Npc, | |
| *, | |
| intent: str, | |
| memory: str | None = None, | |
| ) -> NpcDirective: | |
| return NpcDirective( | |
| npc_id=npc.id, | |
| action="move", | |
| target=target.position, | |
| target_npc_id=target.id, | |
| message=directive.message, | |
| memory=memory or f"You moved toward {target.name}.", | |
| intent=intent, | |
| confidence=directive.confidence, | |
| ) | |
| def flee_directive( | |
| world: WorldState, | |
| npc: Npc, | |
| threat: Npc, | |
| directive: NpcDirective, | |
| ) -> NpcDirective: | |
| half_width = world.terrain.width / 2 | |
| half_depth = world.terrain.depth / 2 | |
| return NpcDirective( | |
| npc_id=npc.id, | |
| action="move", | |
| target=walk_away_target(npc, threat, half_width=half_width, half_depth=half_depth), | |
| target_npc_id=threat.id, | |
| message=directive.message, | |
| memory=f"You backed away from {threat.name}.", | |
| intent="flee_from_threat", | |
| confidence=directive.confidence, | |
| ) | |
| def idle_directive( | |
| directive: NpcDirective, | |
| *, | |
| memory: str | None, | |
| intent: str, | |
| ) -> NpcDirective: | |
| return NpcDirective( | |
| npc_id=directive.npc_id, | |
| action="idle", | |
| target=None, | |
| target_npc_id=directive.target_npc_id, | |
| message=directive.message, | |
| memory=memory, | |
| intent=intent, | |
| confidence=directive.confidence, | |
| ) | |
| def _npc_by_id(world: WorldState, npc_id: str) -> Npc | None: | |
| return next((candidate for candidate in world.living_npcs() if candidate.id == npc_id), None) | |