Skip to main content

amaze/
grid_coord_2d.rs

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); // 4x4 grid
85        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); // 3x3 grid
97        // This should panic as (3, 3) is out of bounds for 0-based indexing
98        grid.linearize_coords(GridCoord2D::new(3, 3));
99    }
100}