board_game/games/go/
link.rs

1// TODO move validness checking here
2
3use crate::games::go::util::OptionU16;
4use std::collections::HashSet;
5
6// TODO remove options here? we either have both present or neither
7// TODO make fields private
8// TODO do a circular linked list instead?
9//   might yield an easier or more compact implementation
10#[derive(Debug, Clone)]
11pub struct LinkHead {
12    pub first: OptionU16,
13    // TODO remove last?
14    pub last: OptionU16,
15    len: u16,
16}
17
18// TODO remove option here, this can be implicit from the containing node
19#[derive(Debug, Clone)]
20pub struct LinkNode {
21    pub prev: OptionU16,
22    pub next: OptionU16,
23}
24
25// TODO allow multiple implementations for the same type?
26//   in theory a value could be part of multiple different linked lists
27//   newtypes are not enough since we currently need the storage to have a matching type
28pub trait Linked {
29    fn link(&self) -> &LinkNode;
30    fn link_mut(&mut self) -> &mut LinkNode;
31}
32
33impl LinkHead {
34    pub fn empty() -> Self {
35        Self::full(0)
36    }
37
38    /// Build the head for a list containing a single value `index`.
39    pub fn single(index: u16) -> Self {
40        LinkHead {
41            first: OptionU16::Some(index),
42            last: OptionU16::Some(index),
43            len: 1,
44        }
45    }
46
47    /// Build the head for a list containing every value in `0..len`.
48    pub fn full(len: u16) -> Self {
49        if len == 0 {
50            LinkHead {
51                first: OptionU16::None,
52                last: OptionU16::None,
53                len: 0,
54            }
55        } else {
56            LinkHead {
57                first: OptionU16::Some(0),
58                last: OptionU16::Some(len - 1),
59                len,
60            }
61        }
62    }
63
64    pub fn pop_front(&mut self, storage: &mut [impl Linked]) -> OptionU16 {
65        let first_id = match self.first.to_option() {
66            None => return OptionU16::None,
67            Some(first_id) => first_id,
68        };
69
70        let first = &mut storage[first_id as usize].link_mut();
71        let next_id = first.next;
72
73        // update first
74        debug_assert_eq!(first.prev, OptionU16::None);
75        first.next = OptionU16::None;
76
77        // update head/next
78        self.first = next_id;
79        self.len -= 1;
80        match next_id.to_option() {
81            None => self.last = next_id,
82            Some(next) => storage[next as usize].link_mut().prev = OptionU16::None,
83        }
84
85        OptionU16::Some(first_id)
86    }
87
88    pub fn insert_front(&mut self, index: u16, storage: &mut [impl Linked]) {
89        let mut other = LinkHead::single(index);
90        self.splice_front_take(&mut other, storage);
91        debug_assert!(other.is_empty());
92    }
93
94    pub fn splice_front_take(&mut self, other: &mut LinkHead, storage: &mut [impl Linked]) {
95        // middle connection
96        if let Some(other_last) = other.last.to_option() {
97            storage[other_last as usize].link_mut().next = self.first;
98        }
99        if let Some(self_first) = self.first.to_option() {
100            storage[self_first as usize].link_mut().prev = other.last;
101        }
102
103        // edges
104        let new_head = LinkHead {
105            first: other.first.or(self.first),
106            last: self.last.or(other.last),
107            len: self.len + other.len,
108        };
109
110        // results
111        *self = new_head;
112        *other = LinkHead::empty();
113    }
114
115    pub fn remove(&mut self, index: u16, storage: &mut [impl Linked]) {
116        let node = storage[index as usize].link_mut();
117        let prev = node.prev.take();
118        let next = node.next.take();
119
120        match prev.to_option() {
121            None => self.first = next,
122            Some(prev) => storage[prev as usize].link_mut().next = next,
123        }
124        match next.to_option() {
125            None => self.last = prev,
126            Some(next) => storage[next as usize].link_mut().prev = prev,
127        }
128
129        self.len -= 1;
130    }
131
132    pub fn len(&self) -> u16 {
133        self.len
134    }
135
136    pub fn is_empty(&self) -> bool {
137        self.len() == 0
138    }
139
140    pub fn iter<'s, L: Linked>(&self, storage: &'s [L]) -> LinkIterator<'s, L> {
141        LinkIterator::new(self, storage)
142    }
143
144    // TODO implement an iterator for this, similar to LinkIterator
145    pub fn for_each_mut<L: Linked>(&self, storage: &mut [L], mut f: impl FnMut(&mut [L], u16)) {
146        let mut next = self.first;
147        let mut prev = OptionU16::None;
148        while let Some(curr) = next.to_option() {
149            let link = storage[curr as usize].link();
150            debug_assert_eq!(prev, link.prev);
151            prev = OptionU16::Some(curr);
152
153            next = link.next;
154            f(storage, curr);
155        }
156    }
157
158    /// Checks whether this list is valid and returns all of the contained nodes.
159    /// In the panic messages "A |-> B" is read as "A points to B but B does not point back".
160    pub fn assert_valid_and_collect(&self, storage: &[impl Linked]) -> HashSet<u16> {
161        let mut seen = HashSet::new();
162
163        match self.first.to_option() {
164            None => assert_eq!(OptionU16::None, self.last, "Wrong last: start |-> end"),
165            Some(first) => assert_eq!(
166                OptionU16::None,
167                storage[first as usize].link().prev,
168                "Wrong prev: start |-> {}",
169                first
170            ),
171        }
172
173        let mut next = self.first;
174        while let Some(curr) = next.to_option() {
175            let inserted = seen.insert(curr);
176            assert!(inserted, "Empty linked list contains loop including {}", curr);
177
178            next = storage[curr as usize].link().next;
179            match next.to_option() {
180                None => assert_eq!(OptionU16::Some(curr), self.last, "Wrong last: {} |-> end", curr),
181                Some(next) => assert_eq!(
182                    OptionU16::Some(curr),
183                    storage[next as usize].link().prev,
184                    "Wrong prev: {} |-> {}",
185                    curr,
186                    next
187                ),
188            }
189        }
190
191        assert_eq!(seen.len(), self.len as usize);
192        seen
193    }
194
195    pub fn map_index(&self, mut f: impl FnMut(u16) -> u16) -> Self {
196        LinkHead {
197            first: self.first.map(&mut f),
198            last: self.last.map(&mut f),
199            len: self.len,
200        }
201    }
202}
203
204impl LinkNode {
205    pub fn single() -> Self {
206        LinkNode {
207            prev: OptionU16::None,
208            next: OptionU16::None,
209        }
210    }
211
212    pub fn full(len: u16, index: u16) -> Self {
213        LinkNode {
214            prev: if index > 0 {
215                OptionU16::Some(index - 1)
216            } else {
217                OptionU16::None
218            },
219            next: if index + 1 < len {
220                OptionU16::Some(index + 1)
221            } else {
222                OptionU16::None
223            },
224        }
225    }
226
227    pub fn is_unconnected_or_single(&self) -> bool {
228        self.prev.is_none() && self.next.is_none()
229    }
230
231    pub fn map_index(&self, mut f: impl FnMut(u16) -> u16) -> Self {
232        LinkNode {
233            prev: self.prev.map(&mut f),
234            next: self.next.map(&mut f),
235        }
236    }
237}
238
239#[derive(Debug)]
240pub struct LinkIterator<'s, L: Linked> {
241    storage: &'s [L],
242    next: OptionU16,
243    items_left: u16,
244}
245
246impl<'s, L: Linked> LinkIterator<'s, L> {
247    pub fn new(head: &LinkHead, storage: &'s [L]) -> Self {
248        Self {
249            storage,
250            next: head.first,
251            items_left: head.len,
252        }
253    }
254}
255
256impl<'s, L: Linked> Iterator for LinkIterator<'s, L> {
257    type Item = u16;
258
259    fn next(&mut self) -> Option<Self::Item> {
260        match self.next.to_option() {
261            None => {
262                debug_assert_eq!(self.items_left, 0);
263                None
264            }
265            Some(index) => {
266                self.next = self.storage[index as usize].link().next;
267                self.items_left -= 1;
268                Some(index)
269            }
270        }
271    }
272
273    fn size_hint(&self) -> (usize, Option<usize>) {
274        (self.len(), Some(self.len()))
275    }
276
277    // TODO optimize nth?
278    // fn nth(&mut self, n: usize) -> Option<Self::Item> {
279    //     println!(
280    //         "calling nth on self={{next: {:?}, last: {:?}, items_left: {}}}, n={}",
281    //         self.next, self.last, self.items_left, n
282    //     );
283    //
284    //     if n >= self.items_left as usize {
285    //         self.next = None;
286    //         self.items_left = 0;
287    //         return None;
288    //     }
289    //
290    //     let item = if n <= (self.items_left / 2) as usize {
291    //         // walk forward
292    //         let mut curr = self.next.unwrap();
293    //         for _ in 0..n {
294    //             curr = self.storage[curr as usize].next.unwrap();
295    //         }
296    //         curr
297    //     } else {
298    //         // walk backwards
299    //         // TODO debug this
300    //         let mut curr = self.last.unwrap();
301    //         for _ in 0..(n - self.items_left as usize - 1) {
302    //             curr = self.storage[curr as usize].prev.unwrap();
303    //         }
304    //         curr
305    //     };
306    //
307    //     self.next = self.storage[item as usize].next;
308    //     self.items_left -= n as u16;
309    //
310    //     Some(item)
311    // }
312}
313
314impl<'s, L: Linked> ExactSizeIterator for LinkIterator<'s, L> {
315    fn len(&self) -> usize {
316        self.items_left as usize
317    }
318}