#![feature(box_patterns)]
extern crate monotonic_solver;
use std::fmt;
use monotonic_solver::{solve_and_reduce, Solver};
use Person::*;
use Expr::*;
use Place::*;
use Weapon::*;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Person {
Alice,
Bob,
Cecil,
Dan,
Erica,
Filip,
Gaia,
Hans,
Ida,
Joel,
Kitty,
Lamar,
Monica,
Nils,
}
impl Person {
pub fn male(&self) -> bool {
match *self {
Alice | Cecil | Erica | Gaia | Ida | Kitty | Monica => false,
Bob | Dan | Filip | Hans | Joel | Lamar | Nils => true
}
}
}
impl fmt::Display for Person {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{:?}", self)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Place {
University,
CoffeeBar,
}
impl fmt::Display for Place {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", match *self {
University => "university",
CoffeeBar => "coffee bar",
})
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Weapon {
Knife,
Gun,
}
impl Weapon {
fn shoots(&self) -> bool {
match *self {
Knife => false,
Gun => true,
}
}
}
impl fmt::Display for Weapon {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", match *self {
Knife => "knife",
Gun => "gun",
})
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum Expr {
HadChild {father: Person, mother: Person, child: Person},
Married {man: Person, woman: Person},
FellInLove {man: Person, woman: Person},
RomanticDinner {man: Person, woman: Person},
MetEachOther {man: Person, woman: Person, at: Place},
WasWorking {person: Person, place: Place},
GotJob {person: Person, place: Place},
AppliedForJob {person: Person, place: Place},
DiedOfCancer(Person),
HadToStayInBedBecauseOfIllness(Person),
GotCancer(Person),
GotSick(Person),
FeltIll(Person),
DiedInCarAccident(Person),
DroveCarToWork(Person),
OwnedCar(Person),
PurchasedCar(Person),
SawAffordableCar(Person),
WasLookingForCar(Person),
NeededCar(Person),
Murdered {murderer: Person, victim: Person, weapon: Weapon},
Shot {attacker: Person, target: Person, weapon: Weapon},
PulledTrigger {person: Person, weapon: Weapon},
Aimed {aimer: Person, target: Person, weapon: Weapon},
}
impl fmt::Display for Expr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
HadChild {father, mother, child} =>
write!(fmt, "{} and {} gave birth to {}", father, mother, child)?,
Married {man, woman} => write!(fmt, "{} married {}", man, woman)?,
FellInLove {man, woman} => write!(fmt, "{} and {} fell in love", man, woman)?,
RomanticDinner {man, woman} =>
write!(fmt, "{} took {} out for a romantic dinner", man, woman)?,
MetEachOther {man, woman, at} =>
write!(fmt, "{} and {} met each other at the {}", man, woman, at)?,
WasWorking {person, place} =>
write!(fmt, "{} was working at the {}", person, place)?,
GotJob {person, place} =>
write!(fmt, "{} got job at the {}", person, place)?,
AppliedForJob {person, place} =>
write!(fmt, "{} applied for job at the {}", person, place)?,
DiedOfCancer(person) => write!(fmt, "{} died of cancer", person)?,
HadToStayInBedBecauseOfIllness(person) =>
write!(fmt, "{} has to stay in bed because of illness", person)?,
GotCancer(person) => write!(fmt, "{} got cancer", person)?,
GotSick(person) => write!(fmt, "{} got sick", person)?,
FeltIll(person) => write!(fmt, "{} felt ill", person)?,
DiedInCarAccident(person) => write!(fmt, "{} died in car accident", person)?,
DroveCarToWork(person) => write!(fmt, "{} drove the car to work", person)?,
OwnedCar(person) => write!(fmt, "{} owned a car", person)?,
PurchasedCar(person) => write!(fmt, "{} purchased a car", person)?,
SawAffordableCar(person) => {
write!(fmt, "{} saw a car {} could affort", person,
if person.male() {"he"} else {"she"})?
}
WasLookingForCar(person) => write!(fmt, "{} was looking for a car", person)?,
NeededCar(person) => write!(fmt, "{} needed a car", person)?,
Murdered {murderer, victim, weapon} =>
write!(fmt, "{} murdered {} with a {}", murderer, victim, weapon)?,
Shot {attacker, target, weapon} =>
write!(fmt, "{} shot {} with a {}", attacker, target, weapon)?,
Aimed {aimer, target, weapon} =>
write!(fmt, "{} aimed the {} at {}", aimer, weapon, target)?,
PulledTrigger {person, weapon} =>
write!(fmt, "{} pulled the trigger of the {}", person, weapon)?,
}
Ok(())
}
}
fn infer(solver: Solver<Expr>, story: &[Expr]) -> Option<Expr> {
let places = &[
University, CoffeeBar
];
for expr in story {
if let &HadChild {father, mother, ..} = expr {
let new_expr = Married {man: father, woman: mother};
if solver.can_add(&new_expr) {return Some(new_expr);}
}
if let &Married {man, woman} = expr {
let new_expr = FellInLove {man, woman};
if solver.can_add(&new_expr) {return Some(new_expr);}
}
if let &FellInLove {man, woman} = expr {
let new_expr = RomanticDinner {man, woman};
if solver.can_add(&new_expr) {return Some(new_expr);}
for place in places {
if solver.cache.contains(&WasWorking {person: man, place: *place}) ||
solver.cache.contains(&WasWorking {person: woman, place: *place}) {
let new_expr = MetEachOther {man, woman, at: *place};
if solver.can_add(&new_expr) {return Some(new_expr);}
}
}
}
if let &WasWorking {person, place} = expr {
let new_expr = GotJob {person, place};
if solver.can_add(&new_expr) {return Some(new_expr);}
}
if let &GotJob {person, place} = expr {
let new_expr = AppliedForJob {person, place};
if solver.can_add(&new_expr) {return Some(new_expr);}
}
if let &DiedOfCancer(person) = expr {
let new_expr = GotCancer(person);
if solver.can_add(&new_expr) {return Some(new_expr);}
let new_expr = HadToStayInBedBecauseOfIllness(person);
if solver.can_add(&new_expr) {return Some(new_expr);}
}
if let &GotCancer(person) = expr {
let new_expr = GotSick(person);
if solver.can_add(&new_expr) {return Some(new_expr);}
}
if let &HadToStayInBedBecauseOfIllness(person) = expr {
let new_expr = GotSick(person);
if solver.can_add(&new_expr) {return Some(new_expr);}
}
if let &GotSick(person) = expr {
let new_expr = FeltIll(person);
if solver.can_add(&new_expr) {return Some(new_expr);}
}
if let &WasWorking {person, ..} = expr {
if solver.cache.contains(&DiedInCarAccident(person)) {
let new_expr = DroveCarToWork(person);
if solver.can_add(&new_expr) {return Some(new_expr);}
}
}
if let &DroveCarToWork(person) = expr {
let new_expr = OwnedCar(person);
if solver.can_add(&new_expr) {return Some(new_expr);}
}
if let &OwnedCar(person) = expr {
let new_expr = PurchasedCar(person);
if solver.can_add(&new_expr) {return Some(new_expr);}
}
if let &PurchasedCar(person) = expr {
let new_expr = SawAffordableCar(person);
if solver.can_add(&new_expr) {return Some(new_expr);}
}
if let &SawAffordableCar(person) = expr {
let new_expr = WasLookingForCar(person);
if solver.can_add(&new_expr) {return Some(new_expr);}
}
if let &WasLookingForCar(person) = expr {
let new_expr = NeededCar(person);
if solver.can_add(&new_expr) {return Some(new_expr);}
}
if let &Murdered {murderer, victim, weapon} = expr {
if weapon.shoots() {
let new_expr = Shot {attacker: murderer, target: victim, weapon};
if solver.can_add(&new_expr) {return Some(new_expr);}
}
}
if let &Shot {attacker, target, weapon} = expr {
let new_expr = PulledTrigger {person: attacker, weapon};
if solver.can_add(&new_expr) {return Some(new_expr);}
if solver.cache.contains(&PulledTrigger {person: attacker, weapon}) {
let new_expr = Aimed {aimer: attacker, target, weapon};
if solver.can_add(&new_expr) {return Some(new_expr);}
}
}
}
None
}
fn main() {
let start = vec![
Murdered {murderer: Bob, victim: Alice, weapon: Gun},
];
let goal = vec![
Aimed {aimer: Bob, target: Alice, weapon: Gun},
];
let filter = vec![];
let order_constraints = vec![];
let (solution, status) = solve_and_reduce(&start, &goal, None, &filter,
&order_constraints, infer);
for expr in solution {
println!("{}", expr);
}
if status.is_err() {
println!("Could not solve");
}
}