Снесарев Максим 308f738c37 [new] add goap agents
2026-01-19 20:45:35 +03:00

412 lines
11 KiB
Python

"""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