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}