goap_ai/
state.rs

1use std::{
2    collections::HashMap,
3    hash::{Hash, Hasher},
4};
5
6use serde::Deserialize;
7
8use crate::Action;
9
10#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
11pub struct State(HashMap<String, i32>);
12
13impl State {
14    pub fn keys(&self) -> impl Iterator<Item = &String> {
15        self.0.keys()
16    }
17
18    pub fn get(&self, key: &str) -> Option<&i32> {
19        self.0.get(key)
20    }
21
22    fn insert(&mut self, key: String, value: i32) {
23        self.0.insert(key, value);
24    }
25
26    // Try applying an action and return a new State if valid
27    pub fn apply(&self, action: &Action) -> Option<Self> {
28        let mut new_props = self.clone();
29        for (key, delta) in &action.deltas {
30            let old_val = *new_props.get(key).unwrap_or(&0);
31            let new_val = old_val + delta;
32            if new_val < 0 {
33                return None;
34            }
35            new_props.insert(key.clone(), new_val);
36        }
37        Some(new_props)
38    }
39}
40
41impl Hash for State {
42    fn hash<H: Hasher>(&self, state: &mut H) {
43        // BTreeMap iterates in sorted key order, so this is deterministic.
44        for (key, value) in &self.0 {
45            key.hash(state);
46            value.hash(state);
47        }
48    }
49}