use crate::{action::Action, datum::Datum, localstate::LocalState};
use bevy_reflect::Reflect;
use std::hash::{Hash, Hasher};
#[derive(Reflect, Clone, Debug, PartialEq)]
pub enum Compare {
Equals(Datum),
NotEquals(Datum),
GreaterThanEquals(Datum),
LessThanEquals(Datum),
}
impl Compare {
pub fn value(&self) -> Datum {
match self {
Compare::Equals(f) => *f,
Compare::NotEquals(f) => *f,
Compare::GreaterThanEquals(f) => *f,
Compare::LessThanEquals(f) => *f,
}
}
}
impl Hash for Compare {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
Compare::Equals(datum) => {
0_u8.hash(state);
datum.hash(state);
}
Compare::NotEquals(datum) => {
1_u8.hash(state);
datum.hash(state);
}
Compare::GreaterThanEquals(datum) => {
2_u8.hash(state);
datum.hash(state);
}
Compare::LessThanEquals(datum) => {
3_u8.hash(state);
datum.hash(state);
}
}
}
}
pub fn compare_values(comparison: &Compare, value: &Datum) -> bool {
match comparison {
Compare::Equals(v) => value == v,
Compare::NotEquals(v) => value != v,
Compare::GreaterThanEquals(v) => value >= v,
Compare::LessThanEquals(v) => value <= v,
}
}
pub fn check_preconditions(state: &LocalState, action: &Action) -> bool {
action.preconditions.iter().all(|(key, value)| {
let state_value = state
.data
.get(key)
.unwrap_or_else(|| panic!("Couldn't find key {:#?} in LocalState", key));
compare_values(value, state_value)
})
}
#[cfg(test)]
mod test {
use crate::compare::check_preconditions;
use crate::compare::compare_values;
use crate::prelude::*;
#[test]
fn test_check_preconditions_empty() {
let state = LocalState::default().with_datum("is_hungry", Datum::Bool(true));
let action = Action::default();
let result = check_preconditions(&state, &action);
assert_eq!(result, true);
}
#[test]
fn test_check_preconditions_true() {
let state = LocalState::default().with_datum("is_hungry", Datum::Bool(true));
let action =
Action::default().with_precondition("is_hungry", Compare::Equals(Datum::Bool(true)));
let result = check_preconditions(&state, &action);
assert_eq!(result, true);
}
#[test]
fn test_check_preconditions_false() {
let state = LocalState::default().with_datum("is_hungry", Datum::Bool(true));
let action =
Action::default().with_precondition("is_hungry", Compare::Equals(Datum::Bool(false)));
let result = check_preconditions(&state, &action);
assert_eq!(result, false);
}
#[test]
fn test_check_preconditions_conflicting_preconditions() {
let state = LocalState::default().with_datum("is_hungry", Datum::Bool(true));
let action = Action::default()
.with_precondition("is_hungry", Compare::Equals(Datum::Bool(false)))
.with_precondition("is_hungry", Compare::Equals(Datum::Bool(true)));
let result = check_preconditions(&state, &action);
assert_eq!(result, false);
let action = Action::default()
.with_precondition("is_hungry", Compare::Equals(Datum::Bool(true)))
.with_precondition("is_hungry", Compare::Equals(Datum::Bool(false)));
let result = check_preconditions(&state, &action);
assert_eq!(result, false);
}
#[test]
fn test_greater_than_equals() {
let cases = vec![
(10, 10, true),
(10, 9, false),
(11, 10, false),
];
for (val1, val2, expected) in cases {
let ret = compare_values(
&Compare::GreaterThanEquals(Datum::I64(val1)),
&Datum::I64(val2),
);
assert_eq!(
ret, expected,
"Expected {} to be greater than or equal to {}, but compare_values returned {:#?}",
val1, val2, ret
);
}
}
#[test]
fn test_less_than_equals() {
let cases = vec![
(10, 10, true),
(10, 9, true),
(11, 10, true),
];
for (val1, val2, expected) in cases {
let ret = compare_values(
&Compare::LessThanEquals(Datum::I64(val1)),
&Datum::I64(val2),
);
assert_eq!(
ret, expected,
"Expected {} to be less than or equal to {}, but compare_values returned {:#?}",
val1, val2, ret
);
}
}
#[test]
fn test_not_equals() {
let cases = vec![
(10, 10, false),
(10, 9, true),
(11, 10, true),
];
for (val1, val2, expected) in cases {
let ret = compare_values(&Compare::NotEquals(Datum::I64(val1)), &Datum::I64(val2));
assert_eq!(
ret, expected,
"Expected {} to not be equal to {}, but compare_values returned {:#?}",
val1, val2, ret
);
}
}
}