three_style_lib/moves/
alg.rs1use crate::{
2 error::Error,
3 moves::core::{Inverse, Move, MoveKind},
4};
5use std::{collections::BTreeMap, fmt, ops::Add, str::FromStr};
6
7#[derive(Debug, Default, PartialEq, Clone)]
8pub struct Alg(Vec<Move>);
9
10impl Alg {
11 pub fn new<T>(moves: T) -> Self
12 where
13 T: IntoIterator<Item = Move>,
14 {
15 Self(moves.into_iter().collect())
16 }
17
18 pub fn len(&self) -> usize {
19 self.0.len()
20 }
21
22 pub fn is_empty(&self) -> bool {
23 self.len() == 0
24 }
25
26 pub fn iter(&self) -> impl Iterator<Item = &Move> {
27 self.0.iter()
28 }
29
30 pub fn reduce(self) -> Self {
31 let mut moves = Vec::new();
32 let mut stack = Vec::new();
33 let mut group: BTreeMap<MoveKind, Move> = BTreeMap::new();
34
35 for m in self.0 {
36 let prev_value = group.remove(&m.kind);
37 let has_prev_value = prev_value.is_some();
38
39 let result = match prev_value {
40 Some(n) => n * m,
41 None => group.contains_key(&m.kind.inverse()).then_some(m),
42 };
43
44 if let Some(value) = result {
45 group.insert(m.kind, value);
46 }
47 if result.is_some() || has_prev_value {
48 continue;
49 }
50
51 while let Some((_, m)) = group.pop_first() {
52 moves.push(m);
53 }
54
55 group.insert(m.kind, m);
56 }
57
58 moves.extend(group.into_values());
59
60 for m in moves {
61 if let Some(&last) = stack.last() {
62 if let Some(result) = last * m {
63 stack.pop();
64 stack.push(result);
65 continue;
66 }
67 }
68
69 stack.push(m);
70 }
71
72 Alg::new(stack)
73 }
74}
75
76impl Inverse for Alg {
77 fn inverse(&self) -> Self {
78 Self(self.0.iter().rev().map(Move::inverse).collect())
79 }
80}
81
82impl IntoIterator for Alg {
83 type Item = Move;
84 type IntoIter = std::vec::IntoIter<Move>;
85
86 fn into_iter(self) -> Self::IntoIter {
87 self.0.into_iter()
88 }
89}
90
91impl FromStr for Alg {
92 type Err = Error;
93
94 fn from_str(s: &str) -> Result<Self, Self::Err> {
95 let moves = s
96 .split_whitespace()
97 .map(Move::from_str)
98 .collect::<Result<Vec<_>, _>>();
99
100 moves.map(Self::new)
101 }
102}
103
104impl Add<Self> for Alg {
105 type Output = Self;
106
107 fn add(self, rhs: Self) -> Self::Output {
108 Self(self.0.into_iter().chain(rhs).collect())
109 }
110}
111
112impl Add<&Alg> for &Alg {
113 type Output = Alg;
114
115 fn add(self, rhs: &Alg) -> Self::Output {
116 self.clone() + rhs.clone()
117 }
118}
119
120impl Add<&Alg> for Alg {
121 type Output = Self;
122
123 fn add(self, rhs: &Alg) -> Self::Output {
124 self + rhs.clone()
125 }
126}
127
128impl fmt::Display for Alg {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 let s = self
131 .0
132 .iter()
133 .map(|m| m.to_string())
134 .collect::<Vec<_>>()
135 .join(" ");
136
137 write!(f, "{s}")
138 }
139}
140
141#[macro_export]
142macro_rules! alg {
143 ($moves: expr) => {{
144 use std::str::FromStr;
145 use $crate::moves::Alg;
146 Alg::from_str($moves).unwrap()
147 }};
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153 use crate::moves::{MoveCount, MoveKind};
154
155 #[test]
156 fn test_basics() {
157 let alg = alg!("R U R' U'");
158 let inverse = alg.inverse();
159
160 assert_eq!(
161 alg,
162 Alg(vec![
163 Move::new(MoveKind::R, MoveCount::Simple),
164 Move::new(MoveKind::U, MoveCount::Simple),
165 Move::new(MoveKind::R, MoveCount::Prime),
166 Move::new(MoveKind::U, MoveCount::Prime)
167 ])
168 );
169
170 assert_eq!(
171 inverse,
172 Alg(vec![
173 Move::new(MoveKind::U, MoveCount::Simple),
174 Move::new(MoveKind::R, MoveCount::Simple),
175 Move::new(MoveKind::U, MoveCount::Prime),
176 Move::new(MoveKind::R, MoveCount::Prime)
177 ])
178 );
179 }
180
181 #[test]
182 fn test_move_reduction() {
183 let alg = alg!("U D2 D U'").reduce();
184 let expected = alg!("D'");
185 assert_eq!(expected, alg);
186
187 let alg = alg!("R U R' U D' U2").reduce();
188 let expected = alg!("R U R' U' D''");
189 assert_eq!(expected, alg);
190
191 let alg = alg!("U2 U2 D D' R").reduce();
192 let expected = alg!("R");
193 assert_eq!(expected, alg);
194
195 let alg = alg!("M R' U r R'").reduce();
196 let expected = alg!("r' U M'");
197 assert_eq!(expected, alg);
198 }
199}