use std::marker::PhantomData;
use cubing::alg::{Alg, AlgNode, Pause};
use crate::{
_internal::{
errors::SearchError, puzzle_traits::puzzle_traits::SemiGroupActionPuzzle,
search::search_logger::SearchLogger,
},
scramble::apply_flat_alg::apply_flat_alg,
};
use super::SearchPhase;
#[derive(Default)]
pub struct MultiPhaseSearchOptions {
pub search_logger: SearchLogger,
pub include_pause_between_phases: bool,
}
pub struct MultiPhaseSearch<TPuzzle: SemiGroupActionPuzzle> {
tpuzzle: TPuzzle,
pub phases: Vec<Box<dyn SearchPhase<TPuzzle>>>,
options: MultiPhaseSearchOptions,
pub phantom_data: PhantomData<TPuzzle>,
}
impl<TPuzzle: SemiGroupActionPuzzle> MultiPhaseSearch<TPuzzle> {
pub fn try_new(
tpuzzle: TPuzzle,
phases: Vec<Box<dyn SearchPhase<TPuzzle>>>,
options: MultiPhaseSearchOptions,
) -> Result<Self, SearchError> {
Ok(Self {
tpuzzle,
phases,
options,
phantom_data: PhantomData,
})
}
pub fn chain_first_solution_for_each_phase(
&mut self,
search_pattern: &TPuzzle::Pattern,
) -> Result<Alg, SearchError> {
let mut current_solution: Option<Alg> = None;
for phase in self.phases.iter_mut() {
self.options
.search_logger
.write_info(&format!("Starting phase: {}", phase.phase_name()));
self.options.search_logger.write_info(&format!(
"Solution so far: {}",
current_solution.clone().unwrap_or_default()
));
let Some(phase_search_pattern) = apply_flat_alg(
&self.tpuzzle,
&search_pattern.clone(),
¤t_solution.clone().unwrap_or_default(),
) else {
return Err(SearchError {
description: format!(
"Could not apply alg to search pattern for phase: {}",
phase.phase_name()
),
});
};
self.options.search_logger.write_info(&format!(
"phase_search_pattern: {:#?}",
phase_search_pattern
));
let Some(phase_solution) = phase.solutions(&phase_search_pattern)?.next() else {
return Err(SearchError {
description: format!(
"Could not find a solution for phase: {}",
phase.phase_name()
),
});
};
current_solution = match current_solution.take() {
Some(current_solution) => Some(Alg {
nodes: [
current_solution.nodes,
if self.options.include_pause_between_phases {
vec![AlgNode::PauseNode(Pause {})]
} else {
vec![]
},
phase_solution.nodes,
]
.concat(),
}),
None => Some(Alg {
nodes: [phase_solution.nodes].concat(),
}),
};
}
Ok(current_solution.expect("No phase solutions?"))
}
}