Skip to main content

grid_search_cardinal_common/
coord.rs

1use direction::CardinalDirection;
2use grid_2d::ICoord;
3#[cfg(feature = "serialize")]
4use serde::{Deserialize, Serialize};
5use std::cmp::Ordering;
6
7#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
8#[derive(Clone, Copy, Debug)]
9pub struct CardinalCoord(ICoord);
10
11#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
12#[derive(Clone, Copy, Debug)]
13pub struct UnitCoord(CardinalCoord);
14
15pub const UNIT_COORDS: [UnitCoord; 4] = [
16    UnitCoord(CardinalCoord(ICoord::new(1, 0))),
17    UnitCoord(CardinalCoord(ICoord::new(0, -1))),
18    UnitCoord(CardinalCoord(ICoord::new(-1, 0))),
19    UnitCoord(CardinalCoord(ICoord::new(0, 1))),
20];
21
22fn is_cardinal(coord: ICoord) -> bool {
23    (coord.x == 0 && coord.y != 0) || (coord.y == 0 && coord.x != 0)
24}
25
26impl CardinalCoord {
27    pub const fn to_coord(self) -> ICoord {
28        self.0
29    }
30    pub fn from_coord(coord: ICoord) -> Option<Self> {
31        if is_cardinal(coord) { Some(Self(coord)) } else { None }
32    }
33    pub const fn left90(self) -> Self {
34        Self(self.0.left90())
35    }
36    pub const fn right90(self) -> Self {
37        Self(self.0.right90())
38    }
39    pub const fn left135(self) -> ICoord {
40        self.0.cardinal_left135()
41    }
42    pub const fn right135(self) -> ICoord {
43        self.0.cardinal_right135()
44    }
45    pub fn to_cardinal_direction(self) -> CardinalDirection {
46        match self.0.x.cmp(&0) {
47            Ordering::Equal => match self.0.y.cmp(&0) {
48                Ordering::Equal => unreachable!(),
49                Ordering::Less => CardinalDirection::North,
50                Ordering::Greater => CardinalDirection::South,
51            },
52            Ordering::Less => CardinalDirection::West,
53            Ordering::Greater => CardinalDirection::East,
54        }
55    }
56    pub const fn magnitude(self) -> u32 {
57        (self.0.x + self.0.y).unsigned_abs()
58    }
59    pub fn to_unit_coord(self) -> UnitCoord {
60        match self.0.x.cmp(&0) {
61            Ordering::Equal => match self.0.y.cmp(&0) {
62                Ordering::Equal => unreachable!(),
63                Ordering::Less => UnitCoord(Self(ICoord::new(0, -1))),
64                Ordering::Greater => UnitCoord(Self(ICoord::new(0, 1))),
65            },
66            Ordering::Less => UnitCoord(Self(ICoord::new(-1, 0))),
67            Ordering::Greater => UnitCoord(Self(ICoord::new(1, 0))),
68        }
69    }
70}
71
72impl UnitCoord {
73    pub const fn left90(self) -> Self {
74        Self(self.0.left90())
75    }
76    pub const fn right90(self) -> Self {
77        Self(self.0.right90())
78    }
79    pub const fn left135(self) -> ICoord {
80        self.0.left135()
81    }
82    pub const fn right135(self) -> ICoord {
83        self.0.right135()
84    }
85    pub const fn to_coord(self) -> ICoord {
86        self.0.to_coord()
87    }
88    pub const fn to_cardinal_coord(self) -> CardinalCoord {
89        self.0
90    }
91    pub fn to_cardinal_direction(self) -> CardinalDirection {
92        self.0.to_cardinal_direction()
93    }
94    pub fn from_cardinal_direction(cardinal_direction: CardinalDirection) -> Self {
95        Self(CardinalCoord(cardinal_direction.coord()))
96    }
97    pub fn scale(self, by: u32) -> CardinalCoord {
98        assert_ne!(by, 0);
99        CardinalCoord(self.to_coord() * by as i32)
100    }
101}