wfc/
tiled_slice.rs

1use crate::orientation::Orientation;
2use coord_2d::*;
3use grid_2d::*;
4use std::hash::{Hash, Hasher};
5
6#[derive(Clone)]
7pub struct TiledGridSlice<'a, T: 'a> {
8    grid: &'a Grid<T>,
9    offset: Coord,
10    size: Size,
11    orientation: Orientation,
12}
13
14pub struct TiledGridSliceIter<'a, T: 'a> {
15    grid: &'a TiledGridSlice<'a, T>,
16    coord_iter: CoordIter,
17}
18
19impl<'a, T> Iterator for TiledGridSliceIter<'a, T> {
20    type Item = &'a T;
21    fn next(&mut self) -> Option<Self::Item> {
22        self.coord_iter
23            .next()
24            .map(|coord| self.grid.get_valid(coord))
25    }
26}
27
28impl<'a, T> TiledGridSlice<'a, T> {
29    pub fn new(
30        grid: &'a Grid<T>,
31        offset: Coord,
32        size: Size,
33        orientation: Orientation,
34    ) -> Self {
35        TiledGridSlice {
36            grid,
37            offset,
38            size,
39            orientation,
40        }
41    }
42    pub fn size(&self) -> Size {
43        self.size
44    }
45    fn get_valid(&self, coord: Coord) -> &'a T {
46        let transformed_coord = self.orientation.transform_coord(self.size, coord);
47        self.grid.get_tiled(self.offset + transformed_coord)
48    }
49    pub fn get_checked(&self, coord: Coord) -> &'a T {
50        if coord.is_valid(self.size) {
51            self.get_valid(coord)
52        } else {
53            panic!("coord is out of bounds");
54        }
55    }
56    pub fn offset(&self) -> Coord {
57        self.offset
58    }
59    pub fn iter(&self) -> TiledGridSliceIter<T> {
60        TiledGridSliceIter {
61            grid: self,
62            coord_iter: CoordIter::new(self.size),
63        }
64    }
65}
66
67impl<'a, T: Hash> Hash for TiledGridSlice<'a, T> {
68    fn hash<H: Hasher>(&self, state: &mut H) {
69        for value in self.iter() {
70            value.hash(state);
71        }
72    }
73}
74
75impl<'a, T: PartialEq> PartialEq for TiledGridSlice<'a, T> {
76    fn eq(&self, other: &Self) -> bool {
77        self.size == other.size && self.iter().zip(other.iter()).all(|(s, o)| s.eq(o))
78    }
79}
80impl<'a, T: Eq> Eq for TiledGridSlice<'a, T> {}
81
82#[cfg(test)]
83mod test {
84    use super::*;
85    use crate::orientation::Orientation;
86    use coord_2d::{Coord, Size};
87    use std::collections::HashSet;
88
89    #[test]
90    fn tiling() {
91        let grid = Grid::new_fn(Size::new(4, 4), |coord| coord);
92        let slice = TiledGridSlice::new(
93            &grid,
94            Coord::new(-1, -1),
95            Size::new(2, 2),
96            Orientation::Original,
97        );
98        let value = *slice.get_valid(Coord::new(0, 1));
99        assert_eq!(value, Coord::new(3, 0));
100    }
101    #[test]
102    fn tiled_grid_slice_hash() {
103        let mut grid = Grid::new_fn(Size::new(4, 4), |_| 0);
104        *grid.get_mut(Coord::new(1, 3)).unwrap() = 1;
105        let size = Size::new(2, 2);
106        let a = TiledGridSlice::new(&grid, Coord::new(0, 0), size, Orientation::Original);
107        let b = TiledGridSlice::new(&grid, Coord::new(2, 2), size, Orientation::Original);
108        let c = TiledGridSlice::new(&grid, Coord::new(0, 2), size, Orientation::Original);
109        let d =
110            TiledGridSlice::new(&grid, Coord::new(1, 2), size, Orientation::Clockwise270);
111        let mut set = HashSet::new();
112        set.insert(a);
113        set.insert(b);
114        set.insert(c);
115        set.insert(d);
116        assert_eq!(set.len(), 2);
117    }
118}