1use std::ops::{Add, Sub};
2
3#[derive(Debug, Default, Eq, PartialEq, Copy, Clone, Ord, PartialOrd, Hash)]
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5pub struct GridCoord2D {
6 pub x: usize,
7 pub y: usize,
8}
9
10impl GridCoord2D {
11 #[inline]
12 pub fn new(x: usize, y: usize) -> Self {
13 Self { x, y }
14 }
15
16 #[inline]
17 pub fn up(&self) -> Option<Self> {
18 self.y.checked_sub(1).map(|y| Self::new(self.x, y))
19 }
20
21 #[inline]
22 pub fn down(&self) -> Option<Self> {
23 self.y.checked_add(1).map(|y| Self::new(self.x, y))
24 }
25
26 #[inline]
27 pub fn left(&self) -> Option<Self> {
28 self.x.checked_sub(1).map(|x| Self::new(x, self.y))
29 }
30
31 #[inline]
32 pub fn right(&self) -> Option<Self> {
33 self.x.checked_add(1).map(|x| Self::new(x, self.y))
34 }
35}
36
37impl Add<GridCoord2D> for GridCoord2D {
38 type Output = Self;
39
40 fn add(self, rhs: GridCoord2D) -> Self::Output {
41 Self::new(self.x + rhs.x, self.y + rhs.y)
42 }
43}
44
45impl Sub<GridCoord2D> for GridCoord2D {
46 type Output = Self;
47
48 fn sub(self, rhs: GridCoord2D) -> Self::Output {
49 Self::new(self.x - rhs.x, self.y - rhs.y)
50 }
51}
52
53pub trait LinearizeCoords2D {
54 fn linearize_coords(&self, coords: GridCoord2D) -> usize;
55}
56
57pub trait GetCoordinateBounds2D {
58 fn width(&self) -> usize;
59 fn height(&self) -> usize;
60}
61
62impl<T> LinearizeCoords2D for T
63where
64 T: GetCoordinateBounds2D,
65{
66 #[inline]
67 fn linearize_coords(&self, coords: GridCoord2D) -> usize {
68 let width = self.width();
69 let height = self.height();
70
71 let coords = coords.y * width + coords.x;
72 assert!(coords < width * height, "Linear index out of bounds");
73 coords
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 use crate::wall4_grid::Wall4Grid;
81
82 #[test]
83 fn linearize_coords_correctly() {
84 let grid = Wall4Grid::new(4, 4); assert_eq!(grid.linearize_coords(GridCoord2D::new(0, 0)), 0);
86 assert_eq!(grid.linearize_coords(GridCoord2D::new(1, 0)), 1);
87 assert_eq!(grid.linearize_coords(GridCoord2D::new(3, 0)), 3);
88 assert_eq!(grid.linearize_coords(GridCoord2D::new(0, 1)), 4);
89 assert_eq!(grid.linearize_coords(GridCoord2D::new(2, 2)), 10);
90 assert_eq!(grid.linearize_coords(GridCoord2D::new(3, 3)), 15);
91 }
92
93 #[test]
94 #[should_panic(expected = "Linear index out of bounds")]
95 fn linearize_coords_out_of_bounds_panics() {
96 let grid = Wall4Grid::new(3, 3); grid.linearize_coords(GridCoord2D::new(3, 3));
99 }
100}