use goap::prelude::*;
fn main() {
let initial_state = State::new()
.set("temperature", 22.5)
.set("heater_on", false)
.set("cooler_on", false)
.set("power_available", 100.0) .build();
let goal = Goal::new("Adjust Temperature")
.requires("temperature", 24.0)
.build();
let turn_on_heater = Action::new("Turn on heater")
.cost(1.0)
.requires("heater_on", false)
.requires("power_available", 20.0) .sets("heater_on", true)
.subtracts("power_available", 20.0)
.build();
let heat_room = Action::new("Heat room")
.cost(2.0)
.requires("heater_on", true)
.requires("power_available", 5.0) .adds("temperature", 0.5) .subtracts("power_available", 5.0) .build();
let turn_on_cooler = Action::new("Turn on cooler")
.cost(1.0)
.requires("cooler_on", false)
.requires("power_available", 30.0) .sets("cooler_on", true)
.subtracts("power_available", 30.0)
.build();
let cool_room = Action::new("Cool room")
.cost(2.0)
.requires("cooler_on", true)
.requires("power_available", 8.0) .subtracts("temperature", 1.0) .subtracts("power_available", 8.0) .build();
let actions = vec![turn_on_heater, heat_room, turn_on_cooler, cool_room];
let planner = Planner::new();
println!("Planning to adjust room temperature...");
println!("Initial state: {initial_state:?}");
println!("Goal state: {goal:?}");
match planner.plan(initial_state.clone(), &goal, &actions) {
Ok(plan) => {
let action_count = plan.actions.len();
let cost = plan.cost;
println!("\nFound 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(temp) = current_state.get::<f64>("temperature") {
println!("Temperature: {temp:.1}°C");
}
if let Some(power) = current_state.get::<f64>("power_available") {
println!("Power available: {power:.1}%");
}
}
}
Err(e) => println!("No plan found! {e}"),
}
}