extern crate monotonic_solver;
use monotonic_solver::{search, Solver};
use Expr::*;
use Fruit::*;
use Taste::*;
use Person::*;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Person {
Hannah,
Peter,
Clara,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Taste {
Sweet,
Sour,
Bitter,
NonSour,
}
impl Taste {
fn likes(&self, fruit: Fruit) -> bool {
*self == Sweet && fruit.is_sweet() ||
*self == Sour && fruit.is_sour() ||
*self == Bitter && fruit.is_bitter() ||
*self == NonSour && !fruit.is_sour()
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Fruit {
Apple,
Grape,
Lemon,
Orange,
}
impl Fruit {
fn is_sweet(&self) -> bool {
match *self {Orange | Apple => true, Grape | Lemon => false}
}
fn is_sour(&self) -> bool {
match *self {Lemon | Orange => true, Apple | Grape => false}
}
fn is_bitter(&self) -> bool {
match *self {Grape | Lemon => true, Apple | Orange => false}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Expr {
ForSale(Fruit),
Preference(Person, Taste, Taste),
Buy(Person, Fruit),
}
fn infer(solver: Solver<Expr>, story: &[Expr]) -> Option<Expr> {
for expr in story {
if let &Preference(x, taste1, taste2) = expr {
for expr2 in story {
if let &ForSale(y) = expr2 {
if taste1.likes(y) && taste2.likes(y) {
let new_expr = Buy(x, y);
if solver.can_add(&new_expr) {return Some(new_expr)};
}
}
}
}
}
None
}
fn main() {
let start = vec![
ForSale(Orange),
ForSale(Grape),
ForSale(Apple),
ForSale(Lemon),
Preference(Hannah, Sour, Bitter),
Preference(Peter, Sour, Sweet),
Preference(Peter, NonSour, Bitter),
Preference(Clara, NonSour, Sweet),
];
let order_constraints = vec![
(Buy(Peter, Grape), Buy(Peter, Orange)),
];
let person = Peter;
let (res, _) = search(
&start,
|expr| if let &Buy(x, y) = expr {if x == person {Some(y)} else {None}} else {None},
Some(1000), &[],
&order_constraints,
infer,
);
println!("{:?} will buy:", person);
for r in res {
println!("- {:?}", r);
}
}