1use std::ops::{Add, Index, IndexMut, Mul, Neg, Range, Sub};
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
7pub struct Point(pub i32, pub i32);
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
11pub struct Size(pub i32, pub i32);
12
13#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
17pub struct Move(pub i32, pub i32);
18
19#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
23pub struct Rotation(i32, i32, i32, i32);
24
25pub const MOVE_UP: Move = Move(-1, 0);
27
28pub const MOVE_RIGHT: Move = Move(0, 1);
30
31pub const MOVE_DOWN: Move = Move(1, 0);
33
34pub const MOVE_LEFT: Move = Move(0, -1);
36
37pub const MOVE_ALL_DIRECTIONS: [Move; 4] = [MOVE_UP, MOVE_RIGHT, MOVE_DOWN, MOVE_LEFT];
39
40pub const MOVE_ALL_ADJACENTS: [Move; 8] = [
42 MOVE_UP,
43 Move(-1, 1),
44 MOVE_RIGHT,
45 Move(1, 1),
46 MOVE_DOWN,
47 Move(1, -1),
48 MOVE_LEFT,
49 Move(-1, -1),
50];
51
52impl Add<Move> for Point {
53 type Output = Point;
54
55 #[inline]
56 fn add(self, other: Move) -> Point {
57 Point(self.0 + other.0, self.1 + other.1)
58 }
59}
60
61impl Sub<Point> for Point {
62 type Output = Move;
63
64 #[inline]
65 fn sub(self, other: Point) -> Move {
66 Move(self.0 - other.0, self.1 - other.1)
67 }
68}
69
70impl Add<Move> for Move {
71 type Output = Move;
72
73 #[inline]
74 fn add(self, other: Move) -> Move {
75 Move(self.0 + other.0, self.1 + other.1)
76 }
77}
78
79impl Sub<Move> for Move {
80 type Output = Move;
81
82 #[inline]
83 fn sub(self, other: Move) -> Move {
84 Move(self.0 - other.0, self.1 - other.1)
85 }
86}
87
88impl Neg for Move {
89 type Output = Move;
90
91 #[inline]
92 fn neg(self) -> Move {
93 Move(-self.0, -self.1)
94 }
95}
96
97impl Mul<i32> for Move {
98 type Output = Move;
99
100 #[inline]
101 fn mul(self, other: i32) -> Move {
102 Move(self.0 * other, self.1 * other)
103 }
104}
105
106pub const ROT_CCW0: Rotation = Rotation(1, 0, 0, 1);
108
109pub const ROT_CCW90: Rotation = Rotation(0, -1, 1, 0);
111
112pub const ROT_CCW180: Rotation = Rotation(-1, 0, 0, -1);
114
115pub const ROT_CCW270: Rotation = Rotation(0, 1, -1, 0);
117
118pub const ROT_H_FLIP: Rotation = Rotation(1, 0, 0, -1);
120
121pub const ROT_V_FLIP: Rotation = Rotation(-1, 0, 0, 1);
123
124impl Mul<Rotation> for Rotation {
125 type Output = Rotation;
126
127 #[inline]
128 fn mul(self, other: Rotation) -> Rotation {
129 Rotation(
130 self.0 * other.0 + self.1 * other.2,
131 self.0 * other.1 + self.1 * other.3,
132 self.2 * other.0 + self.3 * other.2,
133 self.2 * other.1 + self.3 * other.3,
134 )
135 }
136}
137
138impl Mul<Move> for Rotation {
139 type Output = Move;
140
141 #[inline]
142 fn mul(self, other: Move) -> Move {
143 Move(
144 self.0 * other.0 + self.1 * other.1,
145 self.2 * other.0 + self.3 * other.1,
146 )
147 }
148}
149
150#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
152pub struct CellId(usize);
153
154pub const CELL_ID_OUTSIDE: CellId = CellId(0);
156
157impl CellId {
158 #[inline]
160 pub fn new(id: usize) -> CellId {
161 CellId(id)
162 }
163
164 #[inline]
166 pub fn id(self) -> usize {
167 self.0
168 }
169
170 #[inline]
172 pub fn is_outside(self) -> bool {
173 self == CELL_ID_OUTSIDE
174 }
175}
176
177const OUTSIDE_POINT: Point = Point(-1, -1);
179
180pub trait Geom {
182 fn size(&self) -> Size;
184
185 #[inline]
187 fn row(&self) -> i32 {
188 self.size().0
189 }
190
191 #[inline]
193 fn column(&self) -> i32 {
194 self.size().1
195 }
196
197 #[inline]
199 fn cell_len(&self) -> usize {
200 (self.row() * self.column() + 1) as usize
201 }
202
203 #[inline]
205 fn contains(&self, p: Point) -> bool {
206 let size = self.size();
207 0 <= p.0 && p.0 < size.0 && 0 <= p.1 && p.1 < size.1
208 }
209
210 #[inline]
212 fn point_to_cellid(&self, p: Point) -> CellId {
213 if self.contains(p) {
214 CellId::new((p.0 * self.column() + p.1 + 1) as usize)
215 } else {
216 CELL_ID_OUTSIDE
217 }
218 }
219
220 #[inline]
222 fn cellid_to_point(&self, id: CellId) -> Point {
223 if id.is_outside() {
224 OUTSIDE_POINT
225 } else {
226 let idx = id.id() - 1;
227 Point((idx as i32) / self.column(), (idx as i32) % self.column())
228 }
229 }
230
231 #[inline]
233 fn points(&self) -> Points {
234 if self.row() > 0 && self.column() > 0 {
235 Points {
236 point: Some(Point(0, 0)),
237 size: self.size(),
238 }
239 } else {
240 Points {
241 point: None,
242 size: self.size(),
243 }
244 }
245 }
246
247 #[inline]
249 fn points_in_row(&self, row: i32) -> PointsInRow {
250 PointsInRow {
251 row,
252 columns: 0..self.column(),
253 }
254 }
255
256 #[inline]
258 fn points_in_column(&self, column: i32) -> PointsInColumn {
259 PointsInColumn {
260 column,
261 rows: 0..self.row(),
262 }
263 }
264}
265
266#[derive(Copy, Clone, Debug)]
268pub struct Points {
269 point: Option<Point>,
270 size: Size,
271}
272
273impl Iterator for Points {
274 type Item = Point;
275
276 #[inline]
277 fn next(&mut self) -> Option<Point> {
278 if let Some(cur) = self.point {
279 let mut next = cur;
280 let mut end = false;
281 next.1 += 1;
282 if next.1 >= self.size.1 {
283 next.0 += 1;
284 next.1 = 0;
285 if next.0 >= self.size.0 {
286 end = true;
287 }
288 }
289 if !end {
290 self.point = Some(next);
291 } else {
292 self.point = None;
293 }
294 return Some(cur);
295 }
296 None
297 }
298}
299
300#[derive(Clone, Debug)]
302pub struct PointsInRow {
303 row: i32,
304 columns: Range<i32>,
305}
306
307impl Iterator for PointsInRow {
308 type Item = Point;
309
310 #[inline]
311 fn next(&mut self) -> Option<Point> {
312 if let Some(c) = self.columns.next() {
313 Some(Point(self.row, c))
314 } else {
315 None
316 }
317 }
318}
319
320#[derive(Clone, Debug)]
322pub struct PointsInColumn {
323 rows: Range<i32>,
324 column: i32,
325}
326
327impl Iterator for PointsInColumn {
328 type Item = Point;
329
330 #[inline]
331 fn next(&mut self) -> Option<Point> {
332 if let Some(r) = self.rows.next() {
333 Some(Point(r, self.column))
334 } else {
335 None
336 }
337 }
338}
339
340#[derive(Clone, Debug, Eq, PartialEq)]
342pub struct Table<T> {
343 size: Size,
344 data: Vec<T>,
345}
346
347impl<T> Table<T> {
348 #[inline]
350 pub fn new(size: Size, outside: T, mut data: Vec<T>) -> Table<T> {
351 assert_eq!((size.0 * size.1) as usize, data.len());
352 data.insert(0, outside);
353 Table { size, data }
354 }
355
356 #[inline]
358 pub fn new_empty(size: Size, outside: T, init: T) -> Table<T>
359 where
360 T: Clone,
361 {
362 let data = vec![init; (size.0 * size.1) as usize];
363 Table::new(size, outside, data)
364 }
365}
366
367impl<T> Geom for Table<T> {
368 #[inline]
369 fn size(&self) -> Size {
370 self.size
371 }
372}
373
374impl<T> Index<Point> for Table<T> {
375 type Output = T;
376
377 #[inline]
378 fn index(&self, p: Point) -> &T {
379 let idx = self.point_to_cellid(p).id();
380 &self.data[idx]
381 }
382}
383
384impl<T> IndexMut<Point> for Table<T> {
385 #[inline]
386 fn index_mut(&mut self, p: Point) -> &mut T {
387 let idx = self.point_to_cellid(p).id();
388 &mut self.data[idx]
389 }
390}
391
392#[cfg(test)]
393mod tests {
394 use super::*;
395
396 struct Rect(Size);
397 impl Geom for Rect {
398 fn size(&self) -> Size {
399 self.0
400 }
401 }
402
403 #[test]
404 fn points() {
405 let pts = [
406 Point(0, 0),
407 Point(0, 1),
408 Point(0, 2),
409 Point(1, 0),
410 Point(1, 1),
411 Point(1, 2),
412 Point(2, 0),
413 Point(2, 1),
414 Point(2, 2),
415 Point(3, 0),
416 Point(3, 1),
417 Point(3, 2),
418 ];
419 let rect = Rect(Size(4, 3));
420 assert_eq!(&pts[..], &rect.points().collect::<Vec<_>>()[..]);
421 }
422
423 #[test]
424 fn rotate_mat() {
425 let mat = [ROT_CCW0, ROT_CCW90, ROT_CCW180, ROT_CCW270];
426 for i in 0..mat.len() {
427 for j in 0..mat.len() {
428 assert_eq!(mat[(i + j) % mat.len()], mat[i] * mat[j]);
429 }
430 }
431 }
432
433 #[test]
434 fn rotate_point() {
435 let mat = [ROT_CCW0, ROT_CCW90, ROT_CCW180, ROT_CCW270];
436 let vec = [
437 [MOVE_UP, MOVE_LEFT, MOVE_DOWN, MOVE_RIGHT],
438 [
439 MOVE_UP + MOVE_RIGHT,
440 MOVE_LEFT + MOVE_UP,
441 MOVE_DOWN + MOVE_LEFT,
442 MOVE_RIGHT + MOVE_DOWN,
443 ],
444 ];
445 for i in 0..mat.len() {
446 for v in &vec {
447 for j in 0..v.len() {
448 assert_eq!(v[(i + j) % v.len()], mat[i] * v[j]);
449 }
450 }
451 }
452 }
453}