Skip to main content

arimaa_engine/
direction.rs

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}