use crate::{
cube::Move,
method::{Breakdown, BreakdownError, Method, Substep, SubstepSolution},
};
#[macro_export]
macro_rules! method {
( $( $x:ty ), * $(,)? ) => {
{
use crate::method::builder::Custom;
let mut temp_vec = Vec::new();
$(
temp_vec.push(Custom::step::<$x>());
)*
Custom::new(temp_vec)
}
};
}
pub trait CustomSubstep {
fn after_moves(&self, moves: &[Move]) -> Box<dyn CustomSubstep>;
fn apply_moves(&mut self, moves: &[Move]);
fn solved(&self) -> bool;
fn comment(&self) -> &'static str;
}
struct SubstepWrapper<S>(S)
where
S: Substep;
impl<S> SubstepWrapper<S>
where
S: Substep,
{
fn new() -> Self {
Self(S::new())
}
}
impl<S: 'static> CustomSubstep for SubstepWrapper<S>
where
S: Substep,
{
fn after_moves(&self, moves: &[Move]) -> Box<dyn CustomSubstep> {
Box::new(Self(self.0.after_moves(moves)))
}
fn apply_moves(&mut self, moves: &[Move]) {
self.0 = self.0.after_moves(moves);
}
fn solved(&self) -> bool {
self.0.solved()
}
fn comment(&self) -> &'static str {
S::comment()
}
}
pub struct Custom {
steps: Vec<Box<dyn CustomSubstep>>,
}
impl Custom {
pub fn step<S: 'static>() -> Box<dyn CustomSubstep>
where
S: Substep,
{
Box::new(SubstepWrapper::<S>::new())
}
pub fn new(steps: Vec<Box<dyn CustomSubstep>>) -> Custom {
Custom { steps }
}
}
impl Method for Custom {
fn breakdown(&self, scramble: &[Move], solution: &[Move]) -> Result<Breakdown, BreakdownError> {
struct SubstepState {
model: Box<dyn CustomSubstep>,
solved: bool,
}
impl SubstepState {
fn process_move(
&mut self,
breakdown: &mut Vec<SubstepSolution>,
move_buff: &mut Vec<Move>,
mv: Move,
) {
if !self.solved {
self.model = self.model.after_moves(&[mv]);
if self.model.solved() {
breakdown.push(SubstepSolution {
comment: self.model.comment(),
solution: move_buff.to_vec(),
});
*move_buff = vec![];
self.solved = true;
}
}
}
}
let mut breakdown = vec![];
let mut move_buff = vec![];
let mut substep_states = vec![];
for model in &self.steps {
let scrambled = model.after_moves(&scramble);
substep_states.push(SubstepState {
solved: scrambled.solved(),
model: scrambled,
});
}
for mv in solution {
move_buff.push(*mv);
for state in &mut substep_states {
state.process_move(&mut breakdown, &mut move_buff, *mv);
}
}
if move_buff.len() != 0 {
breakdown.push(SubstepSolution {
comment: "DNF",
solution: move_buff,
});
}
Ok(breakdown)
}
}