gol_core/space/
grid.rs

1use crate::{BoardSpaceManager, GridPoint1D, GridPoint2D, GridPoint3D, GridPointND};
2use num_traits::{CheckedDiv, FromPrimitive, PrimInt, ToPrimitive, Unsigned};
3use rayon::prelude::*;
4
5pub enum GridOrigin {
6    Center,
7    Zero,
8}
9
10pub struct Grid<T> {
11    indices: Vec<T>,
12}
13
14pub trait GridFactory<T, U, I>
15where
16    I: Iterator<Item = U>,
17{
18    fn new_with_origin(shape: I, origin: GridOrigin) -> Grid<T>;
19    fn new(shape: I) -> Grid<T> {
20        Self::new_with_origin(shape, GridOrigin::Center)
21    }
22}
23
24impl<T> BoardSpaceManager<T, std::vec::IntoIter<T>, rayon::vec::IntoIter<T>> for Grid<T>
25where
26    T: Clone + Send + Sync,
27{
28    fn indices_iter(&self) -> std::vec::IntoIter<T> {
29        self.indices.clone().into_iter()
30    }
31
32    fn indices_par_iter(&self) -> rayon::vec::IntoIter<T> {
33        self.indices.clone().into_par_iter()
34    }
35}
36
37impl<T, U, I> GridFactory<GridPointND<T>, U, I> for Grid<GridPointND<T>>
38where
39    T: PrimInt + CheckedDiv + std::convert::TryFrom<U> + Send + Sync,
40    U: PrimInt + Unsigned + ToPrimitive + FromPrimitive + Send + Sync,
41    I: Iterator<Item = U>,
42{
43    fn new_with_origin(shape: I, origin: GridOrigin) -> Grid<GridPointND<T>> {
44        let shape_vec: Vec<U> = shape.collect();
45        let indices = Self::indices_vec(&shape_vec, origin);
46        Self { indices }
47    }
48}
49
50impl<T> Grid<GridPointND<T>> {
51    fn indices_vec<U>(shape: &Vec<U>, origin: GridOrigin) -> Vec<GridPointND<T>>
52    where
53        T: PrimInt + CheckedDiv + std::convert::TryFrom<U> + Send + Sync,
54        U: PrimInt + Unsigned + ToPrimitive + FromPrimitive + Send + Sync,
55    {
56        let mut num_cell = U::one();
57        for dim in shape.iter() {
58            num_cell = num_cell * *dim;
59        }
60        let zero_t = T::zero();
61        let two_t = T::one() + T::one();
62        (0..num_cell.to_usize().unwrap())
63            .into_par_iter()
64            .map(|i| {
65                let i = U::from_usize(i).unwrap();
66                let mut res = Vec::new();
67                let mut cur = i;
68                for dim in shape.iter() {
69                    let dim_t = match T::try_from(*dim) {
70                        Ok(val) => val,
71                        Err(_) => panic!("Cannot convert size to index type."),
72                    };
73                    let cur_t = match T::try_from(cur) {
74                        Ok(val) => val,
75                        Err(_) => panic!("Cannot convert size to index type."),
76                    };
77                    let dim_idx = cur_t / dim_t
78                        - match &origin {
79                            GridOrigin::Center => dim_t / two_t,
80                            GridOrigin::Zero => zero_t,
81                        };
82                    res.push(dim_idx);
83                    cur = cur % *dim;
84                }
85                GridPointND::new(res.iter())
86            })
87            .collect()
88    }
89}
90
91impl<T, U, I> GridFactory<GridPoint3D<T>, U, I> for Grid<GridPoint3D<T>>
92where
93    T: PrimInt + FromPrimitive + Send + Sync,
94    U: PrimInt + Unsigned + ToPrimitive + Send + Sync,
95    I: Iterator<Item = U>,
96{
97    fn new_with_origin(shape: I, origin: GridOrigin) -> Grid<GridPoint3D<T>> {
98        let shape_vec: Vec<U> = shape.collect();
99        assert_eq!(shape_vec.len(), 3);
100
101        let (x_len, y_len, z_len) = (shape_vec[0], shape_vec[1], shape_vec[2]);
102
103        let (x_half, y_half, z_half) = match origin {
104            GridOrigin::Zero => (T::zero(), T::zero(), T::zero()),
105            GridOrigin::Center => (
106                T::from_usize(x_len.to_usize().unwrap() / 2).unwrap(),
107                T::from_usize(y_len.to_usize().unwrap() / 2).unwrap(),
108                T::from_usize(z_len.to_usize().unwrap() / 2).unwrap(),
109            ),
110        };
111
112        let mut indices = Vec::new();
113        for cur_x in 0..x_len.to_usize().unwrap() {
114            for cur_y in 0..y_len.to_usize().unwrap() {
115                for cur_z in 0..z_len.to_usize().unwrap() {
116                    indices.push(GridPoint3D {
117                        x: T::from_usize(cur_x).unwrap() - x_half,
118                        y: T::from_usize(cur_y).unwrap() - y_half,
119                        z: T::from_usize(cur_z).unwrap() - z_half,
120                    });
121                }
122            }
123        }
124        Self { indices }
125    }
126}
127
128impl<T, U, I> GridFactory<GridPoint2D<T>, U, I> for Grid<GridPoint2D<T>>
129where
130    T: PrimInt + FromPrimitive + Send + Sync,
131    U: PrimInt + Unsigned + ToPrimitive + Send + Sync,
132    I: Iterator<Item = U>,
133{
134    fn new_with_origin(shape: I, origin: GridOrigin) -> Grid<GridPoint2D<T>> {
135        let shape_vec: Vec<U> = shape.collect();
136        assert_eq!(shape_vec.len(), 2);
137
138        let (x_len, y_len) = (shape_vec[0], shape_vec[1]);
139
140        let (x_half, y_half) = match origin {
141            GridOrigin::Zero => (T::zero(), T::zero()),
142            GridOrigin::Center => (
143                T::from_usize(x_len.to_usize().unwrap() / 2).unwrap(),
144                T::from_usize(y_len.to_usize().unwrap() / 2).unwrap(),
145            ),
146        };
147
148        let mut indices = Vec::new();
149        for cur_x in 0..x_len.to_usize().unwrap() {
150            for cur_y in 0..y_len.to_usize().unwrap() {
151                indices.push(GridPoint2D {
152                    x: T::from_usize(cur_x).unwrap() - x_half,
153                    y: T::from_usize(cur_y).unwrap() - y_half,
154                });
155            }
156        }
157        Self { indices }
158    }
159}
160
161impl<T, U, I> GridFactory<GridPoint1D<T>, U, I> for Grid<GridPoint1D<T>>
162where
163    T: PrimInt + FromPrimitive + Send + Sync,
164    U: PrimInt + Unsigned + ToPrimitive + Send + Sync,
165    I: Iterator<Item = U>,
166{
167    fn new_with_origin(shape: I, origin: GridOrigin) -> Grid<GridPoint1D<T>> {
168        let shape_vec: Vec<U> = shape.collect();
169        assert_eq!(shape_vec.len(), 1);
170
171        let x_len = shape_vec[0];
172
173        let x_half = match origin {
174            GridOrigin::Zero => T::zero(),
175            GridOrigin::Center => T::from_usize(x_len.to_usize().unwrap() / 2).unwrap(),
176        };
177
178        let mut indices = Vec::new();
179        for cur_x in 0..x_len.to_usize().unwrap() {
180            indices.push(GridPoint1D {
181                x: T::from_usize(cur_x).unwrap() - x_half,
182            });
183        }
184        Self { indices }
185    }
186}
187
188#[cfg(test)]
189mod grid_tests {
190    use crate::{
191        BoardSpaceManager, Grid, GridFactory, GridOrigin, GridPoint1D, GridPoint2D, GridPoint3D,
192        GridPointND,
193    };
194    use rayon::prelude::*;
195
196    #[test]
197    fn grid_1d_test_1() {
198        type Point = GridPoint1D<i32>;
199
200        let grid = Box::new(Grid::<Point>::new(vec![10usize].into_iter()))
201            as Box<
202                dyn BoardSpaceManager<
203                    Point,
204                    std::vec::IntoIter<Point>,
205                    rayon::vec::IntoIter<Point>,
206                >,
207            >;
208        let indices: Vec<Point> = grid.indices_iter().collect();
209        let indices_par: Vec<Point> = grid.indices_par_iter().collect();
210        assert_eq!(indices.len(), 10);
211        assert_eq!(indices_par.len(), indices.len());
212    }
213
214    #[test]
215    fn grid_1d_test_2() {
216        type Point = GridPoint1D<i32>;
217
218        let grid = Box::new(Grid::<Point>::new(vec![10usize].into_iter()))
219            as Box<
220                dyn BoardSpaceManager<
221                    Point,
222                    std::vec::IntoIter<Point>,
223                    rayon::vec::IntoIter<Point>,
224                >,
225            >;
226        let indices: Vec<Point> = grid.indices_iter().collect();
227        let indices_par: Vec<Point> = grid.indices_par_iter().collect();
228        assert_eq!(indices.len(), 10);
229        assert_eq!(indices_par.len(), indices.len());
230    }
231
232    #[test]
233    fn grid_2d_test_1() {
234        type Point = GridPoint2D<i64>;
235
236        let grid = Box::new(Grid::<Point>::new(vec![5usize, 10].into_iter()))
237            as Box<
238                dyn BoardSpaceManager<
239                    Point,
240                    std::vec::IntoIter<Point>,
241                    rayon::vec::IntoIter<Point>,
242                >,
243            >;
244        let indices: Vec<Point> = grid.indices_iter().collect();
245        let indices_par: Vec<Point> = grid.indices_par_iter().collect();
246        assert_eq!(indices.len(), 50);
247        assert_eq!(indices_par.len(), indices.len());
248    }
249
250    #[test]
251    fn grid_3d_test_1() {
252        type Point = GridPoint3D<i32>;
253
254        let grid = Box::new(Grid::<Point>::new(vec![5usize, 10, 6].into_iter()))
255            as Box<
256                dyn BoardSpaceManager<
257                    Point,
258                    std::vec::IntoIter<Point>,
259                    rayon::vec::IntoIter<Point>,
260                >,
261            >;
262        let indices: Vec<Point> = grid.indices_iter().collect();
263        let indices_par: Vec<Point> = grid.indices_par_iter().collect();
264        assert_eq!(indices.len(), 300);
265        assert_eq!(indices_par.len(), indices.len());
266    }
267
268    #[test]
269    fn grid_nd_test_1() {
270        type Point = GridPointND<i32>;
271
272        let grid = Box::new(Grid::<Point>::new(vec![5usize, 10, 6, 10].into_iter()))
273            as Box<
274                dyn BoardSpaceManager<
275                    Point,
276                    std::vec::IntoIter<Point>,
277                    rayon::vec::IntoIter<Point>,
278                >,
279            >;
280        let indices: Vec<Point> = grid.indices_iter().collect();
281        let indices_par: Vec<Point> = grid.indices_par_iter().collect();
282        assert_eq!(indices.len(), 3000);
283        assert_eq!(indices_par.len(), indices.len());
284    }
285
286    #[test]
287    fn grid_nd_test_2() {
288        type Point = GridPointND<i32>;
289        let board_shape = vec![2u32, 2, 2, 2, 2];
290
291        let grid_1 = Box::new(Grid::<Point>::new(board_shape.clone().into_iter()))
292            as Box<
293                dyn BoardSpaceManager<
294                    Point,
295                    std::vec::IntoIter<Point>,
296                    rayon::vec::IntoIter<Point>,
297                >,
298            >;
299        let grid_2 = Box::new(Grid::<Point>::new_with_origin(
300            board_shape.into_iter(),
301            GridOrigin::Zero,
302        ))
303            as Box<
304                dyn BoardSpaceManager<
305                    Point,
306                    std::vec::IntoIter<Point>,
307                    rayon::vec::IntoIter<Point>,
308                >,
309            >;
310        let indices_1: Vec<Point> = grid_1.indices_iter().collect();
311        let indices_par_1: Vec<Point> = grid_1.indices_par_iter().collect();
312        let indices_2: Vec<Point> = grid_2.indices_iter().collect();
313        let indices_par_2: Vec<Point> = grid_2.indices_par_iter().collect();
314        assert_eq!(indices_1.len(), 32);
315        assert_eq!(indices_par_1.len(), indices_1.len());
316        assert_eq!(indices_2.len(), indices_1.len());
317        assert_eq!(indices_par_2.len(), indices_1.len());
318    }
319}