Skip to content

Commit

Permalink
feat: wide moves reduction (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
luckasRanarison committed Apr 24, 2024
1 parent daddede commit e46911f
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 45 deletions.
2 changes: 1 addition & 1 deletion three-style-lib/src/commutator/finder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ impl CommutatorFinder {
.current_moves
.is_empty()
.not()
.then_some(Alg::new(self.current_moves.clone()).clean());
.then_some(Alg::new(self.current_moves.clone()).reduce());
let commutator = Commutator {
setup,
interchange,
Expand Down
9 changes: 4 additions & 5 deletions three-style-lib/src/commutator/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,11 @@ impl Commutator {
(&interchange, &self.insertion)
};
let middle = first + second + first.inverse() + second.inverse();
let alg = match &self.setup {

match &self.setup {
Some(setup) => setup + &middle + setup.inverse(),
_ => middle,
};

alg.clean()
}
}
}

Expand Down Expand Up @@ -162,6 +161,6 @@ mod tests {
};
let expected = alg!("D R' D' R U R' D R U' D'");

assert_eq!(expected, commutator.expand());
assert_eq!(expected, commutator.expand().reduce());
}
}
66 changes: 43 additions & 23 deletions three-style-lib/src/moves/alg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,33 +27,49 @@ impl Alg {
self.0.iter()
}

pub fn clean(self) -> Self {
let mut groups: Vec<BTreeMap<MoveKind, Move>> = vec![];
pub fn reduce(self) -> Self {
let mut moves = Vec::new();
let mut stack = Vec::new();
let mut group: BTreeMap<MoveKind, Move> = BTreeMap::new();

for m in self.0 {
if let Some(last) = groups.last_mut() {
let prev_value = last.remove(&m.kind);
let has_prev_value = prev_value.is_some();
let result = match prev_value {
Some(n) => n * m,
None => last.contains_key(&m.kind.inverse()).then_some(m),
};

if let Some(value) = result {
last.insert(m.kind, value);
}
if last.is_empty() {
groups.pop();
}
if result.is_some() || has_prev_value {
let prev_value = group.remove(&m.kind);
let has_prev_value = prev_value.is_some();

let result = match prev_value {
Some(n) => n * m,
None => group.contains_key(&m.kind.inverse()).then_some(m),
};

if let Some(value) = result {
group.insert(m.kind, value);
}
if result.is_some() || has_prev_value {
continue;
}

while let Some((_, m)) = group.pop_first() {
moves.push(m);
}

group.insert(m.kind, m);
}

moves.extend(group.into_values());

for m in moves {
if let Some(&last) = stack.last() {
if let Some(result) = last * m {
stack.pop();
stack.push(result);
continue;
}
}

groups.push([(m.kind, m)].into());
stack.push(m);
}

Alg::new(groups.into_iter().flat_map(|g| g.into_values()))
Alg::new(stack)
}
}

Expand Down Expand Up @@ -163,17 +179,21 @@ mod tests {
}

#[test]
fn test_move_cancelation() {
let alg = alg!("U D2 D U'").clean();
fn test_move_reduction() {
let alg = alg!("U D2 D U'").reduce();
let expected = alg!("D'");
assert_eq!(expected, alg);

let alg = alg!("R U R' U D' U2").clean();
let alg = alg!("R U R' U D' U2").reduce();
let expected = alg!("R U R' U' D''");
assert_eq!(expected, alg);

let alg = alg!("U2 U2 D D' R").clean();
let alg = alg!("U2 U2 D D' R").reduce();
let expected = alg!("R");
assert_eq!(expected, alg);

let alg = alg!("M R' U r R'").reduce();
let expected = alg!("r' U M'");
assert_eq!(expected, alg);
}
}
68 changes: 52 additions & 16 deletions three-style-lib/src/moves/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,57 @@ impl Move {
pub fn new(kind: MoveKind, count: MoveCount) -> Self {
Self { kind, count }
}

fn reduce(&self, rhs: Move) -> Option<Move> {
use {MoveCount as C, MoveKind as M};

let is_inversed = self.count.inverse() == rhs.count;
let is_slice = self.kind.is_slice();
let count = if is_slice { rhs.count } else { self.count }; // determined by wide or side moves

match (self.kind, self.count, rhs.kind, rhs.count) {
// wide move generators
(M::U, _, M::E, _) => Some(Move::new(M::Uw, count)),
(M::E, _, M::D, _) if is_inversed => Some(Move::new(M::Dw, count)),
(M::L, _, M::M, _) => Some(Move::new(M::Lw, count)),
(M::M, _, M::R, _) if is_inversed => Some(Move::new(M::Rw, count)),
(M::F, _, M::S, _) => Some(Move::new(M::Fw, count)),
(M::S, _, M::B, _) if is_inversed => Some(Move::new(M::Bw, count)),

// wide move reduction
(M::R, C::Prime, M::Rw, C::Simple) => Some(Move::new(M::M, C::Prime)),
(M::R, C::Simple, M::Rw, C::Prime) => Some(Move::new(M::M, C::Simple)),
(M::L, C::Prime, M::Lw, C::Simple) => Some(Move::new(M::M, C::Simple)),
(M::L, C::Simple, M::Lw, C::Prime) => Some(Move::new(M::M, C::Prime)),
(M::U, C::Prime, M::Uw, C::Simple) => Some(Move::new(M::E, C::Simple)),
(M::U, C::Simple, M::Uw, C::Prime) => Some(Move::new(M::E, C::Prime)),
(M::D, C::Prime, M::Dw, C::Simple) => Some(Move::new(M::E, C::Prime)),
(M::D, C::Simple, M::Dw, C::Prime) => Some(Move::new(M::E, C::Simple)),
(M::F, C::Prime, M::Fw, C::Simple) => Some(Move::new(M::S, C::Simple)),
(M::F, C::Simple, M::Fw, C::Prime) => Some(Move::new(M::S, C::Prime)),
(M::B, C::Prime, M::Bw, C::Simple) => Some(Move::new(M::S, C::Prime)),
(M::B, C::Simple, M::Bw, C::Prime) => Some(Move::new(M::S, C::Simple)),

(M::M, _, M::Lw, _) if is_inversed => Some(Move::new(M::L, count)),
(M::M, _, M::Rw, _) if self.count == rhs.count => Some(Move::new(M::R, count)),
(M::E, _, M::Uw, _) if is_inversed => Some(Move::new(M::U, count)),
(M::E, _, M::Dw, _) if self.count == rhs.count => Some(Move::new(M::D, count)),
(M::S, _, M::Fw, _) if is_inversed => Some(Move::new(M::F, count)),
(M::S, _, M::Bw, _) if self.count == rhs.count => Some(Move::new(M::B, count)),

// move count reduction
(_, _, _, _) if self.kind == rhs.kind && !is_inversed => {
let kind = self.kind;
let count = match (self.count as usize + rhs.count as usize) % 4 {
2 => MoveCount::Double,
3 => MoveCount::Prime,
_ => MoveCount::Simple,
};
Some(Move { kind, count })
}
_ => None,
}
}
}

impl Inverse for Move {
Expand All @@ -173,22 +224,7 @@ impl Mul<Move> for Move {
type Output = Option<Move>;

fn mul(self, rhs: Move) -> Self::Output {
if rhs.kind != self.kind {
return None;
}

if self.count == rhs.count.inverse() {
return None;
}

let kind = self.kind;
let count = match (self.count as usize + rhs.count as usize) % 4 {
2 => MoveCount::Double,
3 => MoveCount::Prime,
_ => MoveCount::Simple,
};

Some(Move { kind, count })
self.reduce(rhs).or(rhs.reduce(self))
}
}

Expand Down

0 comments on commit e46911f

Please sign in to comment.