Skip to main content

chess/game/
tree.rs

1use std::collections::BTreeMap as Map;
2
3use super::Play;
4
5/// A local index into the game's slot map, which actually stores the moves of the game.
6pub type Slot = u32;
7
8#[derive(Clone, PartialEq)]
9pub struct Tree {
10    next: Slot,
11    slots: Map<Slot, Play>,
12    start: Vec<Slot>,
13}
14
15/// A handle to a node in the tree of variations of a game of chess.
16#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Eq, Ord)]
17pub enum Node {
18    #[default]
19    Start,
20    Play(Slot),
21}
22
23impl Default for Tree {
24    fn default() -> Self {
25        Tree::new()
26    }
27}
28
29impl Tree {
30    pub const fn new() -> Self {
31        Self { next: 0, slots: Map::new(), start: Vec::new() }
32    }
33
34    pub fn contains(&self, slot: Slot) -> bool {
35        self.slots.contains_key(&slot)
36    }
37
38    pub fn play(&self, slot: Slot) -> Option<&Play> {
39        self.slots.get(&slot)
40    }
41
42    pub(super) fn play_mut(&mut self, slot: Slot) -> Option<&mut Play> {
43        self.slots.get_mut(&slot)
44    }
45
46    pub fn slots(&self) -> impl Iterator<Item = Slot> + '_ {
47        self.slots.keys().copied()
48    }
49
50    pub fn plays(&self) -> impl Iterator<Item = &Play> {
51        self.slots.values()
52    }
53
54    // unused for now, added for consistency
55    #[allow(dead_code)]
56    pub(super) fn plays_mut(&mut self) -> impl Iterator<Item = &mut Play> {
57        self.slots.values_mut()
58    }
59
60    pub fn start(&self) -> &[Slot] {
61        &self.start
62    }
63
64    pub(super) fn start_mut(&mut self) -> &mut Vec<Slot> {
65        &mut self.start
66    }
67
68    pub fn options(&self, node: Node) -> &[Slot] {
69        match node {
70            Node::Start => self.start(),
71            Node::Play(slot) => &self.play(slot).expect("slot exists").options,
72        }
73    }
74
75    pub(super) fn options_mut(&mut self, node: Node) -> &mut Vec<Slot> {
76        match node {
77            Node::Start => self.start_mut(),
78            Node::Play(slot) => &mut self.play_mut(slot).expect("slot exists").options,
79        }
80    }
81
82    // Non-public, Game controls play coherence and legality.
83    pub(super) fn insert(&mut self, f: impl FnOnce(Slot) -> Play) -> Slot {
84        let slot = self.next;
85        self.next += 1;
86
87        let play = f(slot);
88        debug_assert_eq!(slot, play.slot);
89        self.slots.insert(slot, play);
90        slot
91    }
92
93    // Could plausibly be public, but would have to return bool to
94    // avoid dangling pointers in the move's follow-on options.
95    pub(super) fn remove(&mut self, slot: Slot) -> bool {
96        let Some(play) = self.slots.remove(&slot) else { return false };
97        for option in &play.options {
98            self.remove(*option);
99        }
100        true
101    }
102}
103
104impl Node {
105    pub fn is_start(&self) -> bool {
106        matches!(self, Self::Start)
107    }
108}
109
110#[cfg(feature = "serde")]
111impl serde::Serialize for Node {
112    fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
113    where
114        S: serde::Serializer,
115    {
116        match self {
117            Self::Start => Option::<Slot>::None.serialize(serializer),
118            Self::Play(slot) => Some(*slot).serialize(serializer),
119        }
120    }
121}
122
123#[cfg(feature = "serde")]
124impl<'de> serde::Deserialize<'de> for Node {
125    fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
126    where
127        D: serde::Deserializer<'de>,
128    {
129        Ok(match Option::<Slot>::deserialize(deserializer)? {
130            Some(slot) => Self::Play(slot),
131            None => Self::Start,
132        })
133    }
134}