1use crate::error::Error;
2use std::{fmt, ops::Mul, str::FromStr};
3
4pub trait Inverse {
5 fn inverse(&self) -> Self;
6}
7
8#[rustfmt::skip]
9#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
10pub enum MoveKind {
11 U, R, F, D, L, B,
12 X, Y, Z, M, E, S,
13 Uw, Rw, Fw, Dw, Lw, Bw,
14}
15
16impl MoveKind {
17 pub fn is_side(self) -> bool {
18 matches!(
19 self,
20 Self::U | Self::R | Self::F | Self::D | Self::L | Self::B
21 )
22 }
23
24 pub fn is_rotation(self) -> bool {
25 matches!(self, Self::X | Self::Y | Self::Z)
26 }
27
28 pub fn is_slice(self) -> bool {
29 matches!(self, Self::M | Self::E | Self::S)
30 }
31
32 pub fn is_wide(self) -> bool {
33 matches!(
34 self,
35 Self::Uw | Self::Rw | Self::Fw | Self::Dw | Self::Lw | Self::Bw
36 )
37 }
38
39 pub fn to_moves(&self) -> [Move; 3] {
40 [
41 Move::new(*self, MoveCount::Simple),
42 Move::new(*self, MoveCount::Double),
43 Move::new(*self, MoveCount::Prime),
44 ]
45 }
46
47 pub fn parallel(&self) -> Vec<MoveKind> {
48 match self {
49 MoveKind::E => vec![MoveKind::U, MoveKind::D],
50 MoveKind::M => vec![MoveKind::R, MoveKind::L],
51 MoveKind::S => vec![MoveKind::F, MoveKind::B],
52 MoveKind::U | MoveKind::D => vec![self.inverse(), MoveKind::E],
53 MoveKind::R | MoveKind::L => vec![self.inverse(), MoveKind::M],
54 MoveKind::F | MoveKind::B => vec![self.inverse(), MoveKind::S],
55 _ => vec![self.inverse()],
56 }
57 }
58}
59
60impl Inverse for MoveKind {
61 fn inverse(&self) -> Self {
62 match self {
63 MoveKind::U => MoveKind::D,
64 MoveKind::R => MoveKind::L,
65 MoveKind::F => MoveKind::B,
66 MoveKind::D => MoveKind::U,
67 MoveKind::L => MoveKind::R,
68 MoveKind::B => MoveKind::F,
69 MoveKind::Uw => MoveKind::Dw,
70 MoveKind::Rw => MoveKind::Lw,
71 MoveKind::Fw => MoveKind::Bw,
72 MoveKind::Dw => MoveKind::Uw,
73 MoveKind::Lw => MoveKind::Rw,
74 MoveKind::Bw => MoveKind::Fw,
75 _ => *self,
76 }
77 }
78}
79
80impl FromStr for MoveKind {
81 type Err = Error;
82
83 fn from_str(s: &str) -> Result<Self, Self::Err> {
84 match s {
85 "U" => Ok(MoveKind::U),
86 "F" => Ok(MoveKind::F),
87 "R" => Ok(MoveKind::R),
88 "B" => Ok(MoveKind::B),
89 "L" => Ok(MoveKind::L),
90 "D" => Ok(MoveKind::D),
91 "M" => Ok(MoveKind::M),
92 "S" => Ok(MoveKind::S),
93 "E" => Ok(MoveKind::E),
94 "x" => Ok(MoveKind::X),
95 "y" => Ok(MoveKind::Y),
96 "z" => Ok(MoveKind::Z),
97 "u" => Ok(MoveKind::Uw),
98 "f" => Ok(MoveKind::Fw),
99 "r" => Ok(MoveKind::Rw),
100 "b" => Ok(MoveKind::Bw),
101 "l" => Ok(MoveKind::Lw),
102 "d" => Ok(MoveKind::Dw),
103 _ => Err(Error::InvalidMove(s.to_owned())),
104 }
105 }
106}
107
108impl fmt::Display for MoveKind {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 write!(f, "{:?}", self)
111 }
112}
113
114#[derive(Debug, PartialEq, Clone, Copy)]
115pub enum MoveCount {
116 Simple = 1,
117 Double = 2,
118 Prime = 3,
119}
120
121impl Inverse for MoveCount {
122 fn inverse(&self) -> Self {
123 match self {
124 MoveCount::Simple => MoveCount::Prime,
125 MoveCount::Double => MoveCount::Double,
126 MoveCount::Prime => MoveCount::Simple,
127 }
128 }
129}
130
131impl FromStr for MoveCount {
132 type Err = Error;
133
134 fn from_str(s: &str) -> Result<Self, Self::Err> {
135 match s {
136 "2" => Ok(MoveCount::Double),
137 "'" => Ok(MoveCount::Prime),
138 "" => Ok(MoveCount::Simple),
139 _ => Err(Error::InvalidMove(s.to_owned())),
140 }
141 }
142}
143
144impl fmt::Display for MoveCount {
145 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146 match self {
147 MoveCount::Simple => write!(f, ""),
148 MoveCount::Double => write!(f, "2"),
149 MoveCount::Prime => write!(f, "'"),
150 }
151 }
152}
153
154#[derive(Debug, PartialEq, Clone, Copy)]
155pub struct Move {
156 pub kind: MoveKind,
157 pub count: MoveCount,
158}
159
160impl Move {
161 pub fn new(kind: MoveKind, count: MoveCount) -> Self {
162 Self { kind, count }
163 }
164
165 fn reduce(&self, rhs: Move) -> Option<Move> {
166 use {MoveCount as C, MoveKind as M};
167
168 let is_inversed = self.count.inverse() == rhs.count;
169 let is_slice = self.kind.is_slice();
170 let count = if is_slice { rhs.count } else { self.count }; match (self.kind, self.count, rhs.kind, rhs.count) {
173 (M::U, _, M::E, _) => Some(Move::new(M::Uw, count)),
175 (M::E, _, M::D, _) if is_inversed => Some(Move::new(M::Dw, count)),
176 (M::L, _, M::M, _) => Some(Move::new(M::Lw, count)),
177 (M::M, _, M::R, _) if is_inversed => Some(Move::new(M::Rw, count)),
178 (M::F, _, M::S, _) => Some(Move::new(M::Fw, count)),
179 (M::S, _, M::B, _) if is_inversed => Some(Move::new(M::Bw, count)),
180
181 (M::R, C::Prime, M::Rw, C::Simple) => Some(Move::new(M::M, C::Prime)),
183 (M::R, C::Simple, M::Rw, C::Prime) => Some(Move::new(M::M, C::Simple)),
184 (M::L, C::Prime, M::Lw, C::Simple) => Some(Move::new(M::M, C::Simple)),
185 (M::L, C::Simple, M::Lw, C::Prime) => Some(Move::new(M::M, C::Prime)),
186 (M::U, C::Prime, M::Uw, C::Simple) => Some(Move::new(M::E, C::Simple)),
187 (M::U, C::Simple, M::Uw, C::Prime) => Some(Move::new(M::E, C::Prime)),
188 (M::D, C::Prime, M::Dw, C::Simple) => Some(Move::new(M::E, C::Prime)),
189 (M::D, C::Simple, M::Dw, C::Prime) => Some(Move::new(M::E, C::Simple)),
190 (M::F, C::Prime, M::Fw, C::Simple) => Some(Move::new(M::S, C::Simple)),
191 (M::F, C::Simple, M::Fw, C::Prime) => Some(Move::new(M::S, C::Prime)),
192 (M::B, C::Prime, M::Bw, C::Simple) => Some(Move::new(M::S, C::Prime)),
193 (M::B, C::Simple, M::Bw, C::Prime) => Some(Move::new(M::S, C::Simple)),
194
195 (M::M, _, M::Lw, _) if is_inversed => Some(Move::new(M::L, count)),
196 (M::M, _, M::Rw, _) if self.count == rhs.count => Some(Move::new(M::R, count)),
197 (M::E, _, M::Uw, _) if is_inversed => Some(Move::new(M::U, count)),
198 (M::E, _, M::Dw, _) if self.count == rhs.count => Some(Move::new(M::D, count)),
199 (M::S, _, M::Fw, _) if is_inversed => Some(Move::new(M::F, count)),
200 (M::S, _, M::Bw, _) if self.count == rhs.count => Some(Move::new(M::B, count)),
201
202 (_, _, _, _) if self.kind == rhs.kind && !is_inversed => {
204 let kind = self.kind;
205 let count = match (self.count as usize + rhs.count as usize) % 4 {
206 2 => MoveCount::Double,
207 3 => MoveCount::Prime,
208 _ => MoveCount::Simple,
209 };
210 Some(Move { kind, count })
211 }
212 _ => None,
213 }
214 }
215}
216
217impl Inverse for Move {
218 fn inverse(&self) -> Self {
219 Self::new(self.kind, self.count.inverse())
220 }
221}
222
223impl Mul<Move> for Move {
224 type Output = Option<Move>;
225
226 fn mul(self, rhs: Move) -> Self::Output {
227 self.reduce(rhs).or(rhs.reduce(self))
228 }
229}
230
231impl FromStr for Move {
232 type Err = Error;
233
234 fn from_str(s: &str) -> Result<Self, Self::Err> {
235 let kind = s.get(..1).unwrap_or_default();
236 let kind = MoveKind::from_str(kind)?;
237 let count = s.get(1..2).unwrap_or_default();
238 let count = MoveCount::from_str(count)?;
239
240 Ok(Self { kind, count })
241 }
242}
243
244impl fmt::Display for Move {
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 write!(f, "{}{}", self.kind, self.count)
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use super::*;
253
254 #[test]
255 fn test_move_str() {
256 assert_eq!(
257 Move::from_str("R"),
258 Ok(Move::new(MoveKind::R, MoveCount::Simple))
259 );
260 assert_eq!(
261 Move::from_str("R2"),
262 Ok(Move::new(MoveKind::R, MoveCount::Double))
263 );
264 assert_eq!(
265 Move::from_str("R'"),
266 Ok(Move::new(MoveKind::R, MoveCount::Prime))
267 );
268 }
269}