Advent of Code solutions
1/// Module containing utilities related to direction and movement.
2use crate::pos::Position;
3
4/// Trait used to define an object that can be used to move around a grid.
5///
6/// This is meant for complex scenarios where you want to move around a grid in a non-standard way.
7/// By implementing this trait you can use various methods from the [Position] struct to move around.
8///
9/// # Implementing
10///
11/// Implementing this trait requires you to define a `get_kernel` method that returns a `Position`.
12/// This position is used to move around the grid by applying it to the current position.
13///
14/// # Examples
15///
16/// ```
17/// use utils::prelude::*;
18///
19/// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
20/// struct RightBy(usize);
21///
22/// impl Movement for RightBy {
23/// fn get_kernel(&self) -> Position {
24/// Position::new(self.0 as isize, 0)
25/// }
26/// }
27///
28/// let pos = Position::new(0, 0);
29/// assert_eq!(pos.move_dir(RightBy(1)), Position::new(1, 0));
30/// ```
31///
32/// # See also
33///
34/// - [Direction] is a simple implementation of this trait.
35/// - [Position] is the main user of this trait.
36///
37pub trait Movement: std::fmt::Debug + Copy + Clone + PartialEq + std::hash::Hash {
38 fn get_kernel(&self) -> Position;
39}
40
41/// The four cardinal directions.
42/// Useful for iterating over all four directions.
43pub const CARDINALS: [Direction; 4] = [
44 Direction::North,
45 Direction::South,
46 Direction::East,
47 Direction::West,
48];
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
51/// The four cardinal directions.
52/// This is a simple implementation of the [Movement] trait.
53///
54/// # Examples
55///
56/// ```
57/// use utils::prelude::*;
58///
59/// let pos = Position::new(0, 0);
60/// assert_eq!(pos.move_dir(Direction::North), Position::new(0, -1));
61/// assert_eq!(pos.move_dir(Direction::South), Position::new(0, 1));
62/// assert_eq!(pos.move_dir(Direction::East), Position::new(1, 0));
63/// assert_eq!(pos.move_dir(Direction::West), Position::new(-1, 0));
64/// ```
65///
66pub enum Direction {
67 North,
68 South,
69 East,
70 West,
71}
72
73impl Direction {
74 /// Returns the direction that is opposite to the current one.
75 ///
76 /// # Examples
77 ///
78 /// ```
79 /// use utils::prelude::*;
80 ///
81 /// assert_eq!(Direction::North.opposite(), Direction::South);
82 /// assert_eq!(Direction::South.opposite(), Direction::North);
83 /// assert_eq!(Direction::East.opposite(), Direction::West);
84 /// assert_eq!(Direction::West.opposite(), Direction::East);
85 /// ```
86 ///
87 pub fn opposite(&self) -> Self {
88 match self {
89 Self::North => Self::South,
90 Self::South => Self::North,
91 Self::East => Self::West,
92 Self::West => Self::East,
93 }
94 }
95
96 /// Returns the direction that is 90 degrees to the current one.
97 ///
98 /// # Examples
99 ///
100 /// ```
101 /// use utils::prelude::*;
102 ///
103 /// assert_eq!(Direction::North.ninety_deg(true), Direction::East);
104 /// assert_eq!(Direction::North.ninety_deg(false), Direction::West);
105 ///
106 /// assert_eq!(Direction::South.ninety_deg(true), Direction::West);
107 /// assert_eq!(Direction::South.ninety_deg(false), Direction::East);
108 /// ```
109 ///
110 pub fn ninety_deg(&self, clockwise: bool) -> Self {
111 match (self, clockwise) {
112 (Self::North, true) => Self::East,
113 (Self::North, false) => Self::West,
114 (Self::South, true) => Self::West,
115 (Self::South, false) => Self::East,
116 (Self::East, true) => Self::South,
117 (Self::East, false) => Self::North,
118 (Self::West, true) => Self::North,
119 (Self::West, false) => Self::South,
120 }
121 }
122}
123
124impl From<Position> for Direction {
125 fn from(pos: Position) -> Self {
126 let pos = pos.normalize();
127 match (pos.x, pos.y) {
128 (0, -1) => Self::North,
129 (0, 1) => Self::South,
130 (1, 0) => Self::East,
131 (-1, 0) => Self::West,
132 _ => panic!("Invalid position"),
133 }
134 }
135}
136
137impl Movement for Direction {
138 fn get_kernel(&self) -> Position {
139 match self {
140 Direction::North => Position::new(0, -1),
141 Direction::South => Position::new(0, 1),
142 Direction::East => Position::new(1, 0),
143 Direction::West => Position::new(-1, 0),
144 }
145 }
146}