use ferroplan::{Options, Session};
const DOM: &str = "
(define (domain homestead) (:requirements :strips :typing :numeric-fluents)
(:types agent place)
(:predicates (at ?a - agent ?p - place) (road ?x ?y - place) (fertile ?p - place))
(:functions (grain))
(:action walk :parameters (?a - agent ?from ?to - place)
:precondition (and (at ?a ?from) (road ?from ?to))
:effect (and (not (at ?a ?from)) (at ?a ?to)))
(:action harvest :parameters (?a - agent ?p - place)
:precondition (and (at ?a ?p) (fertile ?p))
:effect (increase (grain) 1)))";
const PRB: &str = "
(define (problem morning) (:domain homestead)
(:objects vera - agent hut field barn - place)
(:init (at vera hut) (road hut field) (road field hut)
(road field barn) (road barn field) (fertile field) (= (grain) 0))
(:goal (>= (grain) 3)))";
fn main() -> Result<(), String> {
let mut world = Session::new(DOM, PRB, &Options::default())?;
let think = world.replan_budgeted(100_000, Some(256));
assert!(think.solved);
let plan = think.plan.as_ref().unwrap();
println!(
"think 1: {} steps within {} evals",
plan.length, think.statistics.evaluated_states
);
world.set_fact("(at vera hut)", false)?;
world.set_fact("(at vera field)", true)?;
world.set_fluent("(grain)", 1.0)?;
world.set_fluent("(grain)", 0.0)?;
let broken = !world.plan_still_valid(plan, 2);
println!("drift broke the plan: {broken} (suffix replay, zero search)");
let rethink = world.replan_budgeted(100_000, Some(256));
assert!(rethink.solved);
println!(
"rethink after drift: {} steps from the CURRENT state",
rethink.plan.as_ref().unwrap().length
);
let tiny = world.replan_budgeted(1, Some(1));
println!(
"tiny think: solved={} after {} evals (bounded, deterministic)",
tiny.solved, tiny.statistics.evaluated_states
);
let forge_dom = "
(define (domain forge) (:requirements :strips :typing :durative-actions)
(:types smith)
(:predicates (ready ?s - smith) (blade ?s - smith))
(:durative-action forge
:parameters (?s - smith)
:duration (= ?duration 8)
:condition (at start (ready ?s))
:effect (and (at start (not (ready ?s))) (at end (blade ?s)))))";
let forge_prb = "
(define (problem two-blades) (:domain forge)
(:objects anvil-a anvil-b - smith)
(:init (ready anvil-a) (ready anvil-b))
(:goal (and (blade anvil-a) (blade anvil-b))))";
let mut forge = Session::new(forge_dom, forge_prb, &Options::default())?;
let think = forge.replan_budgeted(50_000, Some(128));
assert!(think.solved);
let plan = think.plan.as_ref().unwrap();
println!(
"temporal think: {} steps, makespan {:.3} (concurrent — sequential would be 16)",
plan.length,
plan.makespan.unwrap()
);
for s in &plan.steps {
println!(
" {:>6.3}: {} {} [{}]",
s.time.unwrap(),
s.action,
s.args.join(" "),
s.duration.unwrap()
);
}
forge.set_fact("(blade anvil-a)", true)?;
forge.set_fact("(ready anvil-a)", false)?;
let rethink = forge.replan_budgeted(50_000, Some(128));
assert!(rethink.solved);
println!(
"temporal rethink after drift: {} step(s)",
rethink.plan.as_ref().unwrap().length
);
let market = Session::new(
include_str!("../../../benchmarks/bench/bazaar-chain-domain.pddl"),
include_str!("../../../benchmarks/bench/bazaar-chain.pddl"),
&Options::default(),
)?;
let mut trader = market.fork(); trader.set_goal("(has a0 item3)")?;
let think = trader.replan_budgeted(10_000, Some(64));
assert!(think.solved);
let plan = think.plan.as_ref().unwrap();
println!("barter think: {}-hop trade chain", plan.length);
for s in &plan.steps {
println!(" {} {}", s.action, s.args.join(" "));
}
trader.set_fact("(has v2 item2)", false)?;
trader.set_fact("(has v3 item2)", true)?;
let broken = !trader.plan_still_valid(plan, 0);
let rethink = trader.replan_budgeted(10_000, Some(64));
println!(
"drift broke the chain: {broken}; rethink solved={} — the desire {}",
rethink.solved,
if rethink.solved {
"survives by another route"
} else {
"is IMPOSSIBLE now (honest verdict, no wasted wandering)"
}
);
trader.set_goal("(has a0 item1)")?;
let settle = trader.replan_budgeted(10_000, Some(64));
assert!(settle.solved);
println!(
"retargeted desire: {} step(s) to the reachable rung",
settle.plan.as_ref().unwrap().length
);
Ok(())
}