extern crate monotonic_solver;
use monotonic_solver::{solve, solve_and_reduce, Solver};
use Expr::*;
use Person::*;
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Person {
Alice = 0,
Bob = 1,
Carl = 2,
}
impl Person {
pub fn from(val: u8) -> Option<Person> {
match val {
0 => Some(Alice),
1 => Some(Bob),
2 => Some(Carl),
_ => None,
}
}
}
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Hat {
Blue,
Green,
Yellow,
}
impl Hat {
pub fn from(val: u8) -> Option<Hat> {
match val {
0 => Some(Hat::Blue),
1 => Some(Hat::Green),
2 => Some(Hat::Yellow),
_ => None,
}
}
}
pub struct World {
pub wears: [Option<Hat>; 3],
pub worn: [[bool; 3]; 3],
}
impl World {
pub fn new() -> World {
World {
wears: [None; 3],
worn: [[false; 3]; 3],
}
}
pub fn is_hat_free(&self, hat: Hat) -> bool {
for i in 0..self.wears.len() {
if self.wears[i] == Some(hat) {return false};
}
return true;
}
pub fn update_worn(&mut self) {
for i in 0..self.wears.len() {
if let Some(hat) = self.wears[i] {
self.worn[i][hat as usize] = true;
}
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Expr {
TakesOn(Person, Hat),
TakesOff(Person, Hat),
TakesOffHat(Person),
SwapHats(Person, Person),
TakeAllOff,
Sound,
Wears(Person, Hat),
WearsNoHat(Person),
HaveWorn(Person, Hat),
}
fn infer(solver: Solver<Expr>, story: &[Expr]) -> Option<Expr> {
let ref mut world = World::new();
for expr in story {
if let TakesOn(a, hat) = *expr {
if !world.is_hat_free(hat) {return None};
if world.wears[a as usize].is_some() {
return None;
} else {
world.wears[a as usize] = Some(hat);
}
}
if let TakesOff(a, hat) = *expr {
if world.wears[a as usize].is_none() {
return None;
} else if world.wears[a as usize].unwrap() != hat {
return None;
} else {
world.wears[a as usize] = None;
}
}
if let TakesOffHat(a) = *expr {
world.wears[a as usize] = None;
}
if let SwapHats(a, b) = *expr {
world.wears.swap(a as usize, b as usize);
}
if let TakeAllOff = *expr {
for i in 0..world.wears.len() {
world.wears[i] = None;
}
}
world.update_worn();
}
for i in 0..world.wears.len() {
if let Some(person) = Person::from(i as u8) {
if let Some(hat) = world.wears[i] {
let new_expr = Wears(person, hat);
if solver.can_add(&new_expr) {return Some(new_expr)};
} else {
let new_expr = WearsNoHat(person);
if solver.can_add(&new_expr) {return Some(new_expr)};
}
}
}
for i in 0..world.worn.len() {
for j in 0..world.worn[i].len() {
if world.worn[i][j] {
if let Some(person) = Person::from(i as u8) {
if let Some(hat) = Hat::from(j as u8) {
let new_expr = HaveWorn(person, hat);
if solver.can_add(&new_expr) {return Some(new_expr)};
}
}
}
}
}
Some(Sound)
}
pub fn trivial() -> (Vec<Expr>, Vec<Expr>) {
(
vec![
TakesOn(Alice, Hat::Blue),
],
vec![
Sound,
]
)
}
pub fn hats_colliding() -> (Vec<Expr>, Vec<Expr>) {
(
vec![
TakesOn(Alice, Hat::Blue),
TakesOn(Alice, Hat::Green),
],
vec![
Sound,
]
)
}
pub fn take_on_off() -> (Vec<Expr>, Vec<Expr>) {
(
vec![
TakesOn(Alice, Hat::Blue),
TakesOff(Alice, Hat::Blue),
],
vec![
Sound,
]
)
}
pub fn take_off_wrong() -> (Vec<Expr>, Vec<Expr>) {
(
vec![
TakesOn(Alice, Hat::Blue),
TakesOff(Alice, Hat::Green),
],
vec![
Sound,
]
)
}
pub fn take_off_empty() -> (Vec<Expr>, Vec<Expr>) {
(
vec![
TakesOff(Alice, Hat::Green),
],
vec![
Sound,
]
)
}
pub fn bob_and_alice_wears_different_hats() -> (Vec<Expr>, Vec<Expr>) {
(
vec![
TakesOn(Alice, Hat::Green),
TakesOn(Bob, Hat::Blue),
],
vec![
Sound,
]
)
}
pub fn alice_and_bob_tries_to_put_on_same_hat() -> (Vec<Expr>, Vec<Expr>) {
(
vec![
TakesOn(Alice, Hat::Green),
TakesOn(Bob, Hat::Green),
],
vec![
Sound,
]
)
}
pub fn check(fs: &[(fn() -> (Vec<Expr>, Vec<Expr>), bool)]) {
for (i, &(f, ok)) in fs.iter().enumerate() {
let (start, goal) = f();
let order_constraints = vec![];
let (_, status) = solve(
&start,
&goal,
None,
&[],
&order_constraints,
infer,
);
if status.is_ok() != ok {
panic!("Failed check `{}`", i);
}
}
}
pub fn test() -> (Vec<Expr>, Vec<Expr>) {
(
vec![
TakesOn(Alice, Hat::Green),
TakesOn(Bob, Hat::Blue),
TakesOn(Carl, Hat::Yellow),
SwapHats(Alice, Carl),
TakesOffHat(Alice),
],
vec![
WearsNoHat(Alice),
Wears(Bob, Hat::Blue),
Wears(Carl, Hat::Green),
HaveWorn(Alice, Hat::Green),
HaveWorn(Alice, Hat::Yellow),
Sound,
]
)
}
fn main() {
check(&[
(trivial, true),
(hats_colliding, false),
(take_on_off, true),
(take_off_wrong, false),
(take_off_empty, false),
(bob_and_alice_wears_different_hats, true),
(alice_and_bob_tries_to_put_on_same_hat, false),
]);
let (start, goal) = test();
let order_constraints = vec![
];
let (res, status) = solve_and_reduce(
&start,
&goal,
None,
&[],
&order_constraints,
infer,
);
if status.is_ok() {
println!("OK");
} else {
println!("ERROR");
}
for r in res {
println!("{:?}", r);
}
}