use std::str::FromStr;
use super::{get_move_face, get_put_move};
use crate::cubie::Edge::{self, *};
use crate::error::Error;
use crate::facelet::Color;
use crate::{
cubie::CubieCube,
moves::Move::{self, *},
};
pub struct DaisySolver {
pub cube: CubieCube,
}
impl DaisySolver {
pub fn solve(&mut self) -> Vec<Move> {
let mut solution = Vec::new();
let cc = CubieCube::default();
let mut d_edges = Vec::new();
for edge in [DR, DF, DL, DB] {
let _edge = self.get_edge(edge).unwrap();
if _edge.1 <= 3 && _edge.2 == 0 {
} else if _edge.1 >= 8 {
d_edges.push((edge, 1));
} else if (_edge.1 >= 4 && _edge.1 < 8) && _edge.2 == 0 {
d_edges.push((edge, 2));
} else {
d_edges.push((edge, 3));
}
}
d_edges.sort_by_key(|e| e.1);
for edge in d_edges {
let _edge = self.get_edge(edge.0).unwrap();
if _edge.1 <= 3 {
if _edge.2 == 0 {
continue;
} else if _edge.2 == 1 {
let faces = format!("{:?}", cc.ep[_edge.1 as usize]);
let faces = faces.as_str();
let face = faces[1..2].to_string();
let step = Move::from_str(&face).unwrap();
self.cube = self.cube.apply_move(step);
solution.push(step);
let _edge = self.get_edge(edge.0).unwrap();
let step = self.get_move(self.get_edge(edge.0).unwrap()).unwrap();
for i in 0..4 {
let mut u_put = get_put_move(i, U);
let _cube = self.cube;
self.cube = self.cube.apply_moves(&u_put);
let face = get_move_face(step);
if self.is_empty_u_slot(face) {
let step = Move::from_str(step.to_string().as_str()).unwrap();
self.cube = self.cube.apply_move(step);
solution.append(&mut u_put);
solution.push(step);
break;
}
self.cube = _cube;
}
}
} else if _edge.1 >= 4 && _edge.1 < 8 {
if _edge.2 == 0 {
let _edge = self.get_edge(edge.0).unwrap();
let step = self.get_move(self.get_edge(edge.0).unwrap()).unwrap();
for i in 0..4 {
let mut u_put = get_put_move(i, U);
let _cube = self.cube;
self.cube = self.cube.apply_moves(&u_put);
let face = get_move_face(step);
if self.is_empty_u_slot(face) {
let step = Move::from_str(step.to_string().as_str()).unwrap();
self.cube = self.cube.apply_move(step);
solution.append(&mut u_put);
solution.push(step);
break;
}
self.cube = _cube;
}
} else {
let faces = format!("{:?}", cc.ep[_edge.1 as usize]);
let faces = faces.as_str();
let face = faces[1..2].to_string();
let step = Move::from_str(&face).unwrap();
for i in 0..4 {
let mut u_put = get_put_move(i, U);
let _cube = self.cube;
self.cube = self.cube.apply_moves(&u_put);
let face = get_move_face(step);
if self.is_empty_u_slot(face) {
self.cube = self.cube.apply_move(step);
solution.append(&mut u_put);
solution.push(step);
break;
}
self.cube = _cube;
}
let _edge = self.get_edge(edge.0).unwrap();
let step = self.get_move(self.get_edge(edge.0).unwrap()).unwrap();
for i in 0..4 {
let mut u_put = get_put_move(i, U);
let _cube = self.cube;
self.cube = self.cube.apply_moves(&u_put);
let face = get_move_face(step);
if self.is_empty_u_slot(face) {
let step = Move::from_str(step.to_string().as_str()).unwrap();
self.cube = self.cube.apply_move(step);
solution.append(&mut u_put);
solution.push(step);
break;
}
self.cube = _cube;
}
}
} else {
let _edge = self.get_edge(edge.0).unwrap();
let step = self.get_move(self.get_edge(edge.0).unwrap()).unwrap();
for i in 0..4 {
let mut u_put = get_put_move(i, U);
let _cube = self.cube;
self.cube = self.cube.apply_moves(&u_put);
let face = get_move_face(step);
if self.is_empty_u_slot(face) {
let step = Move::from_str(step.to_string().as_str()).unwrap();
self.cube = self.cube.apply_move(step);
solution.append(&mut u_put);
solution.push(step);
break;
}
self.cube = _cube;
}
}
}
solution
}
pub fn is_solved(&self) -> bool {
for edge in [DR, DF, DL, DB] {
if !self.cube.ep[0..4].contains(&edge) {
return false;
}
}
for i in 0..4 {
if self.cube.eo[i] != 0 {
return false;
}
}
true
}
fn get_edge(&self, edge: Edge) -> Result<(Edge, u8, u8), Error> {
for i in 0..12 {
if self.cube.ep[i] == edge {
return Ok((edge, i as u8, self.cube.eo[i]));
}
}
Err(Error::InvalidEdge)
}
fn is_empty_u_slot(&self, face: Color) -> bool {
let edge = format!("U{:?}", face);
let ei = Edge::try_from(edge.as_str()).unwrap() as usize;
if self.cube.eo[ei] == 1 {
return true;
} else if [DR, DF, DL, DB].contains(&self.cube.ep[ei]) {
return false;
}
true
}
fn get_move(&self, edge: (Edge, u8, u8)) -> Result<Move, Error> {
let cc = CubieCube::default();
let _edge = cc.ep[edge.1 as usize];
match _edge {
FR => match edge.2 {
0 => Ok(R),
_ => Ok(F3),
},
FL => match edge.2 {
0 => Ok(L3),
_ => Ok(F),
},
BR => match edge.2 {
0 => Ok(R3),
_ => Ok(B),
},
BL => match edge.2 {
0 => Ok(L),
_ => Ok(B3),
},
DL => match edge.2 {
0 => Ok(L2),
_ => Err(Error::InvalidEdge),
},
DR => match edge.2 {
0 => Ok(R2),
_ => Err(Error::InvalidEdge),
},
DB => match edge.2 {
0 => Ok(B2),
_ => Err(Error::InvalidEdge),
},
DF => match edge.2 {
0 => Ok(F2),
_ => Err(Error::InvalidEdge),
},
_ => Err(Error::InvalidEdge),
}
}
}
#[cfg(test)]
mod tests {
use crate::{cubie::CubieCube, moves::Formula, solver::lbl::daisy::DaisySolver};
#[test]
fn test_daisy() {
let cc = CubieCube::default();
let moves = Formula::scramble();
let cc = cc.apply_formula(&moves);
let cc2 = cc.clone();
let mut daisy = DaisySolver { cube: cc };
let _cs = daisy.solve();
assert!(daisy.is_solved());
let cc2 = cc2.apply_moves(&_cs);
assert_eq!(cc2, daisy.cube);
println!("Scramble: {:?}\nSolution: {:?}", moves, _cs);
}
}