"""Predefined goals for GOAP agents. Goals are organized into categories: - Survival goals: Immediate needs (thirst, hunger, heat, energy) - Resource goals: Building reserves - Economic goals: Trading and wealth building """ from .goal import Goal, GoalType, create_survival_goal, create_resource_stock_goal, create_economic_goal from .world_state import WorldState # ============================================================================= # SURVIVAL GOALS # ============================================================================= def _create_satisfy_thirst_goal() -> Goal: """Satisfy immediate thirst.""" return create_survival_goal( goal_type=GoalType.SATISFY_THIRST, name="Satisfy Thirst", stat_name="thirst", target_pct=0.5, # Want to get to 50% base_priority=15.0, # Highest base priority - thirst is most dangerous ) def _create_satisfy_hunger_goal() -> Goal: """Satisfy immediate hunger.""" return create_survival_goal( goal_type=GoalType.SATISFY_HUNGER, name="Satisfy Hunger", stat_name="hunger", target_pct=0.5, base_priority=12.0, ) def _create_maintain_heat_goal() -> Goal: """Maintain body heat.""" return create_survival_goal( goal_type=GoalType.MAINTAIN_HEAT, name="Maintain Heat", stat_name="heat", target_pct=0.5, base_priority=10.0, ) def _create_restore_energy_goal() -> Goal: """Restore energy when low.""" def is_satisfied(state: WorldState) -> bool: return state.energy_pct >= 0.4 def get_priority(state: WorldState) -> float: if state.energy_pct >= 0.4: return 0.0 # Priority increases as energy decreases urgency = (0.4 - state.energy_pct) / 0.4 # But not if we have more urgent survival needs max_vital_urgency = max(state.thirst_urgency, state.hunger_urgency, state.heat_urgency) if max_vital_urgency > 1.5: # Critical survival need - don't rest return 0.0 base_priority = 6.0 * urgency # Evening boost - want energy for night if state.is_evening: base_priority *= 1.5 return base_priority return Goal( goal_type=GoalType.RESTORE_ENERGY, name="Restore Energy", is_satisfied=is_satisfied, get_priority=get_priority, target_state={"energy_pct": 0.6}, max_plan_depth=1, # Just rest ) SURVIVAL_GOALS = [ _create_satisfy_thirst_goal(), _create_satisfy_hunger_goal(), _create_maintain_heat_goal(), _create_restore_energy_goal(), ] # ============================================================================= # RESOURCE GOALS # ============================================================================= def _create_stock_water_goal() -> Goal: """Maintain water reserves.""" def is_satisfied(state: WorldState) -> bool: target = int(2 * (0.5 + state.hoarding_rate)) return state.water_count >= target def get_priority(state: WorldState) -> float: target = int(2 * (0.5 + state.hoarding_rate)) if state.water_count >= target: return 0.0 deficit = target - state.water_count base_priority = 4.0 * (deficit / max(1, target)) # Lower if urgent survival needs if max(state.thirst_urgency, state.hunger_urgency) > 1.0: base_priority *= 0.3 # Evening boost if state.is_evening: base_priority *= 2.0 return base_priority return Goal( goal_type=GoalType.STOCK_WATER, name="Stock Water", is_satisfied=is_satisfied, get_priority=get_priority, max_plan_depth=2, ) def _create_stock_food_goal() -> Goal: """Maintain food reserves (meat + berries).""" def is_satisfied(state: WorldState) -> bool: target = int(3 * (0.5 + state.hoarding_rate)) return state.food_count >= target def get_priority(state: WorldState) -> float: target = int(3 * (0.5 + state.hoarding_rate)) if state.food_count >= target: return 0.0 deficit = target - state.food_count base_priority = 4.0 * (deficit / max(1, target)) # Lower if urgent survival needs if max(state.thirst_urgency, state.hunger_urgency) > 1.0: base_priority *= 0.3 # Evening boost if state.is_evening: base_priority *= 2.0 # Risk-takers may prefer hunting (more food per action) base_priority *= (0.8 + state.risk_tolerance * 0.4) return base_priority return Goal( goal_type=GoalType.STOCK_FOOD, name="Stock Food", is_satisfied=is_satisfied, get_priority=get_priority, max_plan_depth=2, ) def _create_stock_wood_goal() -> Goal: """Maintain wood reserves for fires.""" def is_satisfied(state: WorldState) -> bool: target = int(2 * (0.5 + state.hoarding_rate)) return state.wood_count >= target def get_priority(state: WorldState) -> float: target = int(2 * (0.5 + state.hoarding_rate)) if state.wood_count >= target: return 0.0 deficit = target - state.wood_count base_priority = 3.0 * (deficit / max(1, target)) # Higher priority if heat is becoming an issue if state.heat_urgency > 0.5: base_priority *= 1.5 # Lower if urgent survival needs if max(state.thirst_urgency, state.hunger_urgency) > 1.0: base_priority *= 0.3 return base_priority return Goal( goal_type=GoalType.STOCK_WOOD, name="Stock Wood", is_satisfied=is_satisfied, get_priority=get_priority, max_plan_depth=2, ) def _create_get_clothes_goal() -> Goal: """Get clothes for heat protection.""" def is_satisfied(state: WorldState) -> bool: return state.has_clothes def get_priority(state: WorldState) -> float: if state.has_clothes: return 0.0 # Only pursue if we have hide if state.hide_count < 1: return 0.0 base_priority = 2.0 # Higher if heat is an issue if state.heat_urgency > 0.3: base_priority *= 1.5 return base_priority return Goal( goal_type=GoalType.GET_CLOTHES, name="Get Clothes", is_satisfied=is_satisfied, get_priority=get_priority, max_plan_depth=1, ) RESOURCE_GOALS = [ _create_stock_water_goal(), _create_stock_food_goal(), _create_stock_wood_goal(), _create_get_clothes_goal(), ] # ============================================================================= # ECONOMIC GOALS # ============================================================================= def _create_build_wealth_goal() -> Goal: """Accumulate money through trading.""" def is_satisfied(state: WorldState) -> bool: return state.is_wealthy def get_priority(state: WorldState) -> float: if state.is_wealthy: return 0.0 # Base priority scaled by wealth desire base_priority = 2.0 * state.wealth_desire # Only when survival is stable max_urgency = max(state.thirst_urgency, state.hunger_urgency, state.heat_urgency) if max_urgency > 0.5: return 0.0 # Traders prioritize wealth more if state.is_trader: base_priority *= 2.0 return base_priority return create_economic_goal( goal_type=GoalType.BUILD_WEALTH, name="Build Wealth", is_satisfied=is_satisfied, get_priority=get_priority, ) def _create_sell_excess_goal() -> Goal: """Sell excess resources on the market.""" def is_satisfied(state: WorldState) -> bool: # Satisfied if inventory is not getting full return state.inventory_space > 3 def get_priority(state: WorldState) -> float: if state.inventory_space > 5: return 0.0 # Plenty of space # Priority increases as inventory fills fullness = 1.0 - (state.inventory_space / 12.0) base_priority = 3.0 * fullness # Low hoarders sell more readily base_priority *= (1.5 - state.hoarding_rate) # Only when survival is stable max_urgency = max(state.thirst_urgency, state.hunger_urgency) if max_urgency > 0.5: base_priority *= 0.5 return base_priority return create_economic_goal( goal_type=GoalType.SELL_EXCESS, name="Sell Excess", is_satisfied=is_satisfied, get_priority=get_priority, ) def _create_find_deals_goal() -> Goal: """Find good deals on the market.""" def is_satisfied(state: WorldState) -> bool: # This goal is never fully "satisfied" - it's opportunistic return False def get_priority(state: WorldState) -> float: # Only pursue if we have money and market access if state.money < 10: return 0.0 # Check if there are deals available has_deals = state.can_buy_water or state.can_buy_food or state.can_buy_wood if not has_deals: return 0.0 # Base priority from market affinity base_priority = 2.0 * state.market_affinity # Only when survival is stable max_urgency = max(state.thirst_urgency, state.hunger_urgency) if max_urgency > 0.5: return 0.0 # Need inventory space if state.inventory_space < 2: return 0.0 return base_priority return create_economic_goal( goal_type=GoalType.FIND_DEALS, name="Find Deals", is_satisfied=is_satisfied, get_priority=get_priority, ) def _create_trader_arbitrage_goal() -> Goal: """Trader-specific arbitrage goal (buy low, sell high).""" def is_satisfied(state: WorldState) -> bool: return False # Always looking for opportunities def get_priority(state: WorldState) -> float: # Only for traders if not state.is_trader: return 0.0 # Need capital to trade if state.money < 20: return 1.0 # Low priority - need to sell something first # Base priority for traders base_priority = 5.0 # Only when survival is stable max_urgency = max(state.thirst_urgency, state.hunger_urgency, state.heat_urgency) if max_urgency > 0.3: base_priority *= 0.5 return base_priority return create_economic_goal( goal_type=GoalType.TRADER_ARBITRAGE, name="Trader Arbitrage", is_satisfied=is_satisfied, get_priority=get_priority, ) def _create_sleep_goal() -> Goal: """Sleep at night.""" def is_satisfied(state: WorldState) -> bool: return not state.is_night # Satisfied when it's not night def get_priority(state: WorldState) -> float: if not state.is_night: return 0.0 # Highest priority at night return 100.0 return Goal( goal_type=GoalType.SLEEP, name="Sleep", is_satisfied=is_satisfied, get_priority=get_priority, max_plan_depth=1, ) ECONOMIC_GOALS = [ _create_build_wealth_goal(), _create_sell_excess_goal(), _create_find_deals_goal(), _create_trader_arbitrage_goal(), _create_sleep_goal(), ] def get_all_goals() -> list[Goal]: """Get all available goals.""" return SURVIVAL_GOALS + RESOURCE_GOALS + ECONOMIC_GOALS