1use anyhow::anyhow;
2use std::convert::TryFrom;
3use std::fmt;
4use std::str::FromStr;
5use strum::IntoEnumIterator;
6use strum_macros::EnumIter;
7
8#[derive(Clone, Copy, Debug, EnumIter, Eq, Hash, PartialEq)]
9#[derive(Default)]
10pub enum Direction {
11 #[default]
12 Up,
13 Right,
14 Down,
15 Left,
16}
17
18
19#[derive(Clone, Copy, Debug, EnumIter, Eq, Hash, PartialEq)]
20#[derive(Default)]
21pub enum MoveDirection {
22 #[default]
23 N,
24 E,
25 S,
26 W,
27 NN,
28 NE,
29 NW,
30 EE,
31 ES,
32 SS,
33 SW,
34 WW,
35 NNN,
36 NNE,
37 NNW,
38 NEE,
39 NWW,
40 EEE,
41 EES,
42 ESS,
43 SSS,
44 SSW,
45 SWW,
46 WWW,
47 NNNN,
48 NNNE,
49 NNNW,
50 NNEE,
51 NNWW,
52 NEEE,
53 NWWW,
54 EEEE,
55 EEES,
56 EESS,
57 ESSS,
58 SSSS,
59 SSSW,
60 SSWW,
61 SWWW,
62 WWWW,
63}
64
65impl MoveDirection {
66 #[rustfmt::skip]
67 pub fn directions(&self) -> Vec<Direction> {
68 match self {
69 MoveDirection::N => vec![Direction::Up ],
70 MoveDirection::E => vec![Direction::Right],
71 MoveDirection::S => vec![Direction::Down ],
72 MoveDirection::W => vec![Direction::Left ],
73 MoveDirection::NN => vec![Direction::Up, Direction::Up ],
74 MoveDirection::NE => vec![Direction::Up, Direction::Right],
75 MoveDirection::NW => vec![Direction::Up, Direction::Left ],
76 MoveDirection::EE => vec![Direction::Right, Direction::Right],
77 MoveDirection::ES => vec![Direction::Right, Direction::Down ],
78 MoveDirection::SS => vec![Direction::Down, Direction::Down ],
79 MoveDirection::SW => vec![Direction::Down, Direction::Left ],
80 MoveDirection::WW => vec![Direction::Left, Direction::Left ],
81 MoveDirection::NNN => vec![Direction::Up, Direction::Up, Direction::Up ],
82 MoveDirection::NNE => vec![Direction::Up, Direction::Up, Direction::Right],
83 MoveDirection::NNW => vec![Direction::Up, Direction::Up, Direction::Left ],
84 MoveDirection::NEE => vec![Direction::Up, Direction::Right, Direction::Right],
85 MoveDirection::NWW => vec![Direction::Up, Direction::Left, Direction::Left ],
86 MoveDirection::EEE => vec![Direction::Right, Direction::Right, Direction::Right],
87 MoveDirection::EES => vec![Direction::Right, Direction::Right, Direction::Down ],
88 MoveDirection::ESS => vec![Direction::Right, Direction::Down, Direction::Down ],
89 MoveDirection::SSS => vec![Direction::Down, Direction::Down, Direction::Down ],
90 MoveDirection::SSW => vec![Direction::Down, Direction::Down, Direction::Left ],
91 MoveDirection::SWW => vec![Direction::Down, Direction::Left, Direction::Left ],
92 MoveDirection::WWW => vec![Direction::Left, Direction::Left, Direction::Left ],
93 MoveDirection::NNNN => vec![Direction::Up, Direction::Up, Direction::Up, Direction::Up ],
94 MoveDirection::NNNE => vec![Direction::Up, Direction::Up, Direction::Up, Direction::Right],
95 MoveDirection::NNNW => vec![Direction::Up, Direction::Up, Direction::Up, Direction::Left ],
96 MoveDirection::NNEE => vec![Direction::Up, Direction::Up, Direction::Right, Direction::Right],
97 MoveDirection::NNWW => vec![Direction::Up, Direction::Up, Direction::Left, Direction::Left ],
98 MoveDirection::NEEE => vec![Direction::Up, Direction::Right, Direction::Right, Direction::Right],
99 MoveDirection::NWWW => vec![Direction::Up, Direction::Left, Direction::Left, Direction::Left ],
100 MoveDirection::EEEE => vec![Direction::Right, Direction::Right, Direction::Right, Direction::Right],
101 MoveDirection::EEES => vec![Direction::Right, Direction::Right, Direction::Right, Direction::Down ],
102 MoveDirection::EESS => vec![Direction::Right, Direction::Right, Direction::Down, Direction::Down ],
103 MoveDirection::ESSS => vec![Direction::Right, Direction::Down, Direction::Down, Direction::Down ],
104 MoveDirection::SSSS => vec![Direction::Down, Direction::Down, Direction::Down, Direction::Down ],
105 MoveDirection::SSSW => vec![Direction::Down, Direction::Down, Direction::Down, Direction::Left ],
106 MoveDirection::SSWW => vec![Direction::Down, Direction::Down, Direction::Left, Direction::Left ],
107 MoveDirection::SWWW => vec![Direction::Down, Direction::Left, Direction::Left, Direction::Left ],
108 MoveDirection::WWWW => vec![Direction::Left, Direction::Left, Direction::Left, Direction::Left ],
109 }
110 }
111
112 pub fn move_directions() -> Vec<MoveDirection> {
113 vec![
114 MoveDirection::N,
115 MoveDirection::E,
116 MoveDirection::S,
117 MoveDirection::W,
118 MoveDirection::NN,
119 MoveDirection::NE,
120 MoveDirection::NW,
121 MoveDirection::EE,
122 MoveDirection::ES,
123 MoveDirection::SS,
124 MoveDirection::SW,
125 MoveDirection::WW,
126 MoveDirection::NNN,
127 MoveDirection::NNE,
128 MoveDirection::NNW,
129 MoveDirection::NEE,
130 MoveDirection::NWW,
131 MoveDirection::EEE,
132 MoveDirection::EES,
133 MoveDirection::ESS,
134 MoveDirection::SSS,
135 MoveDirection::SSW,
136 MoveDirection::SWW,
137 MoveDirection::WWW,
138 MoveDirection::NNNN,
139 MoveDirection::NNNE,
140 MoveDirection::NNNW,
141 MoveDirection::NNEE,
142 MoveDirection::NNWW,
143 MoveDirection::NEEE,
144 MoveDirection::NWWW,
145 MoveDirection::EEEE,
146 MoveDirection::EEES,
147 MoveDirection::EESS,
148 MoveDirection::ESSS,
149 MoveDirection::SSSS,
150 MoveDirection::SSSW,
151 MoveDirection::SSWW,
152 MoveDirection::SWWW,
153 MoveDirection::WWWW,
154 ]
155 }
156}
157
158impl TryFrom<&[Direction]> for MoveDirection {
159 type Error = anyhow::Error;
160
161 fn try_from(dirs: &[Direction]) -> Result<Self, Self::Error> {
162 let vector = |dirs: &[Direction]| -> (i8, i8) {
163 dirs.iter().fold((0, 0), |(mut x, mut y), dir| {
164 match dir {
165 Direction::Up => y += 1,
166 Direction::Right => x += 1,
167 Direction::Down => y -= 1,
168 Direction::Left => x -= 1,
169 };
170 (x, y)
171 })
172 };
173
174 let dir_vector = vector(dirs);
175
176 MoveDirection::iter()
177 .find(|move_direction| vector(&move_direction.directions()) == dir_vector)
178 .ok_or_else(|| anyhow!("No matching MoveDirection for {:?}", dirs))
179 }
180}
181
182
183impl Direction {
184 pub fn invert(&self) -> Self {
185 match self {
186 Direction::Up => Direction::Down,
187 Direction::Right => Direction::Left,
188 Direction::Down => Direction::Up,
189 Direction::Left => Direction::Right,
190 }
191 }
192
193 pub fn vertical_symmetry(&self) -> Self {
194 match self {
195 Direction::Up => Direction::Up,
196 Direction::Right => Direction::Left,
197 Direction::Down => Direction::Down,
198 Direction::Left => Direction::Right,
199 }
200 }
201}
202
203impl TryFrom<char> for Direction {
204 type Error = anyhow::Error;
205
206 fn try_from(c: char) -> Result<Direction, anyhow::Error> {
207 match c {
208 'n' => Ok(Direction::Up),
209 'e' => Ok(Direction::Right),
210 's' => Ok(Direction::Down),
211 'w' => Ok(Direction::Left),
212 _ => Err(anyhow!("Invalid character for Direction")),
213 }
214 }
215}
216
217impl fmt::Display for Direction {
218 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
219 let dir = match self {
220 Direction::Up => 'n',
221 Direction::Right => 'e',
222 Direction::Down => 's',
223 Direction::Left => 'w',
224 };
225
226 write!(f, "{}", dir)
227 }
228}
229
230impl FromStr for Direction {
231 type Err = anyhow::Error;
232
233 fn from_str(s: &str) -> Result<Self, Self::Err> {
234 let mut chars = s.chars();
235 match chars.next() {
236 Some(c) => match chars.next() {
237 None => Direction::try_from(c),
238 Some(_) => Err(anyhow!("More than one char found for Direction: {}", s)),
239 },
240 None => Err(anyhow!("No char found for Direction: {}", s)),
241 }
242 }
243}