ae_direction/
direction.rs

1use std::fmt::Display;
2
3use rand::{distributions::Standard, prelude::Distribution};
4
5#[derive(PartialEq, Clone, Debug)]
6pub enum Cardinal {
7    North,
8    East,
9    South,
10    West,
11}
12
13impl Display for Cardinal {
14    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15        match self {
16            Cardinal::North => write!(f, "north"),
17            Cardinal::East => write!(f, "east"),
18            Cardinal::South => write!(f, "south"),
19            Cardinal::West => write!(f, "west"),
20        }
21    }
22}
23
24#[derive(PartialEq, Clone, Debug)]
25pub enum Ordinal {
26    Northeast,
27    Southeast,
28    Southwest,
29    Northwest,
30}
31
32impl Display for Ordinal {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        match self {
35            Ordinal::Northeast => write!(f, "northeast"),
36            Ordinal::Southeast => write!(f, "southeast"),
37            Ordinal::Southwest => write!(f, "southwest"),
38            Ordinal::Northwest => write!(f, "northwest"),
39        }
40    }
41}
42
43/// Represents a direction, either cardinal or ordinal
44#[derive(PartialEq, Clone, Debug)]
45pub enum Direction {
46    Cardinal(Cardinal),
47    Ordinal(Ordinal),
48}
49
50impl Distribution<Cardinal> for Standard {
51    fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Cardinal {
52        match rng.gen_range(0..=3) {
53            0 => Cardinal::North,
54            1 => Cardinal::East,
55            2 => Cardinal::South,
56            3 => Cardinal::West,
57            _ => unreachable!(),
58        }
59    }
60}
61
62impl Direction {
63    /// Returns the opposite (180 degrees) direction of a `Direction`
64    pub fn reverse(&self) -> Direction {
65        match self {
66            Direction::Cardinal(cardinal) => match cardinal {
67                Cardinal::North => Direction::Cardinal(Cardinal::South),
68                Cardinal::East => Direction::Cardinal(Cardinal::West),
69                Cardinal::South => Direction::Cardinal(Cardinal::North),
70                Cardinal::West => Direction::Cardinal(Cardinal::East),
71            },
72            Direction::Ordinal(ordinal) => match ordinal {
73                Ordinal::Northeast => Direction::Ordinal(Ordinal::Southwest),
74                Ordinal::Southeast => Direction::Ordinal(Ordinal::Northwest),
75                Ordinal::Southwest => Direction::Ordinal(Ordinal::Northeast),
76                Ordinal::Northwest => Direction::Ordinal(Ordinal::Southeast),
77            },
78        }
79    }
80
81    /// Returns the clockwise (90 degrees) direction of a `Direction`
82    pub fn clockwise(&self) -> Direction {
83        match self {
84            Direction::Cardinal(cardinal) => match cardinal {
85                Cardinal::North => Direction::Cardinal(Cardinal::East),
86                Cardinal::East => Direction::Cardinal(Cardinal::South),
87                Cardinal::South => Direction::Cardinal(Cardinal::West),
88                Cardinal::West => Direction::Cardinal(Cardinal::North),
89            },
90            Direction::Ordinal(ordinal) => match ordinal {
91                Ordinal::Northeast => Direction::Ordinal(Ordinal::Southeast),
92                Ordinal::Southeast => Direction::Ordinal(Ordinal::Southwest),
93                Ordinal::Southwest => Direction::Ordinal(Ordinal::Northwest),
94                Ordinal::Northwest => Direction::Ordinal(Ordinal::Northeast),
95            },
96        }
97    }
98}
99
100impl Display for Direction {
101    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102        match self {
103            Direction::Cardinal(cardinal) => write!(f, "{}", cardinal),
104            Direction::Ordinal(ordinal) => write!(f, "{}", ordinal),
105        }
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112
113    #[test]
114    fn clockwise() {
115        let dir = Direction::Cardinal(Cardinal::North);
116        assert_eq!(dir.clockwise(), Direction::Cardinal(Cardinal::East));
117
118        let dir = Direction::Ordinal(Ordinal::Southwest);
119        assert_eq!(dir.clockwise(), Direction::Ordinal(Ordinal::Northwest));
120    }
121
122    #[test]
123    fn reverse() {
124        let dir = Direction::Cardinal(Cardinal::North);
125        assert_eq!(dir.reverse(), Direction::Cardinal(Cardinal::South));
126
127        let dir = Direction::Ordinal(Ordinal::Southwest);
128        assert_eq!(dir.reverse(), Direction::Ordinal(Ordinal::Northeast));
129    }
130}