use goap::prelude::*;
fn main() {
let initial_state = State::new()
.set("gold", 1000)
.set("total_profit", 0)
.set("reputation", 0)
.set("storage_space", 100)
.set("used_storage", 0)
.set("grain", 0)
.set("ore", 0)
.set("textiles", 0)
.set("market_knowledge", 0)
.set("trade_routes", 1)
.set("has_caravan", false)
.set("has_warehouse", false)
.set("has_guild_membership", false)
.build();
let goal = Goal::new("master_merchant")
.requires("total_profit", 2000)
.requires("reputation", 50)
.requires("trade_routes", 2)
.requires("has_guild_membership", true)
.build();
let join_guild = Action::new("join_guild")
.cost(5.0)
.requires("gold", 1500)
.requires("reputation", 30)
.requires("has_guild_membership", false)
.subtracts("gold", 1500)
.sets("has_guild_membership", true)
.adds("market_knowledge", 20)
.adds("reputation", 20)
.build();
let buy_warehouse = Action::new("buy_warehouse")
.cost(10.0)
.requires("gold", 2000)
.requires("has_warehouse", false)
.subtracts("gold", 2000)
.sets("has_warehouse", true)
.adds("storage_space", 200)
.adds("reputation", 10)
.build();
let buy_caravan = Action::new("buy_caravan")
.cost(8.0)
.requires("gold", 1500)
.requires("has_caravan", false)
.subtracts("gold", 1500)
.sets("has_caravan", true)
.adds("trade_routes", 1)
.build();
let buy_grain = Action::new("buy_grain_bulk")
.cost(2.0)
.requires("gold", 500)
.requires("storage_space", 50)
.requires("used_storage", 0)
.subtracts("gold", 500)
.adds("grain", 50)
.adds("used_storage", 50)
.build();
let buy_ore = Action::new("buy_ore_bulk")
.cost(3.0)
.requires("gold", 800)
.requires("storage_space", 40)
.requires("used_storage", 0)
.subtracts("gold", 800)
.adds("ore", 40)
.adds("used_storage", 40)
.build();
let buy_textiles = Action::new("buy_textiles_bulk")
.cost(4.0)
.requires("gold", 1000)
.requires("storage_space", 30)
.requires("used_storage", 0)
.subtracts("gold", 1000)
.adds("textiles", 30)
.adds("used_storage", 30)
.build();
let sell_grain_local = Action::new("sell_grain_local")
.cost(1.0)
.requires("grain", 50)
.adds("gold", 600)
.subtracts("grain", 50)
.subtracts("used_storage", 50)
.adds("total_profit", 100)
.adds("reputation", 5)
.build();
let sell_grain_distant = Action::new("sell_grain_distant")
.cost(3.0)
.requires("grain", 50)
.requires("has_caravan", true)
.adds("gold", 800)
.subtracts("grain", 50)
.subtracts("used_storage", 50)
.adds("total_profit", 300)
.adds("reputation", 10)
.build();
let sell_ore_local = Action::new("sell_ore_local")
.cost(1.0)
.requires("ore", 40)
.adds("gold", 1000)
.subtracts("ore", 40)
.subtracts("used_storage", 40)
.adds("total_profit", 200)
.adds("reputation", 8)
.build();
let sell_ore_distant = Action::new("sell_ore_distant")
.cost(3.0)
.requires("ore", 40)
.requires("has_caravan", true)
.adds("gold", 1400)
.subtracts("ore", 40)
.subtracts("used_storage", 40)
.adds("total_profit", 600)
.adds("reputation", 15)
.build();
let sell_textiles_local = Action::new("sell_textiles_local")
.cost(1.0)
.requires("textiles", 30)
.adds("gold", 1300)
.subtracts("textiles", 30)
.subtracts("used_storage", 30)
.adds("total_profit", 300)
.adds("reputation", 10)
.build();
let sell_textiles_distant = Action::new("sell_textiles_distant")
.cost(3.0)
.requires("textiles", 30)
.requires("has_caravan", true)
.adds("gold", 1800)
.subtracts("textiles", 30)
.subtracts("used_storage", 30)
.adds("total_profit", 800)
.adds("reputation", 20)
.build();
let establish_route = Action::new("establish_trade_route")
.cost(15.0)
.requires("gold", 3000)
.requires("has_guild_membership", true)
.requires("reputation", 40)
.subtracts("gold", 3000)
.adds("trade_routes", 1)
.adds("reputation", 30)
.build();
let actions = vec![
join_guild,
buy_warehouse,
buy_caravan,
buy_grain,
buy_ore,
buy_textiles,
sell_grain_local,
sell_grain_distant,
sell_ore_local,
sell_ore_distant,
sell_textiles_local,
sell_textiles_distant,
establish_route,
];
let planner = Planner::new();
match planner.plan(initial_state.clone(), &goal, &actions) {
Ok(plan) => {
let action_count = plan.actions.len();
let cost = plan.cost;
println!("\nFound trading plan with {action_count} actions and cost {cost:.2}:");
let mut current_state = initial_state;
for (i, action) in plan.actions.iter().enumerate() {
let step = i + 1;
let name = &action.name;
println!("\nStep {step}: {name}");
current_state = action.apply_effect(¤t_state);
if let Some(gold) = current_state.get::<i64>("gold") {
println!("Gold: {gold}");
}
if let Some(profit) = current_state.get::<i64>("total_profit") {
println!("Profit: {profit}");
}
if let Some(reputation) = current_state.get::<i64>("reputation") {
println!("Reputation: {reputation}");
}
if let Some(routes) = current_state.get::<i64>("trade_routes") {
println!("Trade Routes: {routes}");
}
if let Some(guild) = current_state.get::<bool>("has_guild_membership") {
if guild {
println!("Guild Member: Yes");
}
}
if let Some(caravan) = current_state.get::<bool>("has_caravan") {
if caravan {
println!("Has Caravan: Yes");
}
}
if let Some(warehouse) = current_state.get::<bool>("has_warehouse") {
if warehouse {
println!("Has Warehouse: Yes");
}
}
}
}
Err(e) => println!("No plan found! {e}"),
}
}