use super::Solver;
use crate::game::{Game, SimpleGame, DecomposableGame};
use crate::moves::{SimpleGameMoveSorter, DecomposableGameMoveSorter, ComponentsInfo};
use crate::dbs::{NimbersProvider, NimbersStorer};
use crate::nimber_set::NimberSet;
use crate::stats::{StatsCollector, ProgressReporter};
pub trait LVSimpleGameSolver<G> where G: for<'a> SimpleGame<'a> {
fn has_nimber_lv(&mut self, position: &G::Position, nim: u8) -> bool;
fn nimber_lv_classic_report_progress<PR: ProgressReporter>(&mut self, position: G::Position, progress_reporter: PR) -> u8;
#[inline(always)] fn nimber_lv_classic(&mut self, position: G::Position) -> u8 {
self.nimber_lv_classic_report_progress(position, ())
}
}
pub trait LVDecomposableGameSolver<G> where G: for<'c> DecomposableGame<'c> {
fn has_nimber_lv(&mut self, position: &G::Position, nim: u8) -> bool;
fn nimber_of_component_lv_report_progress<PR: ProgressReporter>(&mut self, position: G::Position, progress_reporter: PR) -> u8;
#[inline(always)] fn nimber_of_component_lv(&mut self, position: G::Position) -> u8 {
self.nimber_of_component_lv_report_progress(position, ())
}
fn nimber_lv_report_progress<PR: ProgressReporter + Clone>(&mut self, position: <G as DecomposableGame<'_>>::DecomposablePosition, progress_reporter: PR) -> u8;
#[inline(always)] fn nimber_lv(&mut self, position: <G as DecomposableGame<'_>>::DecomposablePosition) -> u8 {
self.nimber_lv_report_progress(position, ())
}
}
impl<G, TT, EDB, SORTER, STATS> LVSimpleGameSolver<G> for Solver<'_, G, TT, EDB, SORTER, STATS>
where G: for <'a> SimpleGame<'a>,
TT: NimbersProvider<G::Position> + NimbersStorer<G::Position>,
EDB: NimbersProvider<G::Position>,
SORTER: SimpleGameMoveSorter<G>,
STATS: StatsCollector,
G::Position: Clone {
fn has_nimber_lv(&mut self, position: &G::Position, nim: u8) -> bool {
self.stats.pre();
let moves_count = self.game.moves_count(position);
if moves_count < nim as u16 {
self.stats.unknown();
return false;
}
if let Some(v) = self.nimber_from_tt(&position) { self.stats.db_cut(v);
return v == nim;
}
self.stats.etc();
let mut moves: Vec::<G::Position> = Vec::with_capacity(moves_count as usize);
for m in self.game.successors(&position) {
if let Some(v) = self.nimber_from_any_db(&m) {
if v == nim { self.stats.db_cut(v);
return false;
}
} else {
moves.push(m);
}
}
self.move_sorter.sort_moves(&self.game, &mut moves);
self.stats.recursive();
if (0..nim).any(|new_nim| self.has_nimber_lv(&s, new_nim)) {
self.stats.unknown();
return false;
}
if moves.iter().any(|m| self.has_nimber_lv(&m, nim)) {
self.stats.unknown();
return false; }
self.transposition_table.store_nimber(position.clone(), nim);
self.stats.exact(nim);
true
}
fn nimber_lv_report_progress<PR: ProgressReporter>(&mut self, position: G::Position, mut progress_reporter: PR) -> u8 {
self.stats.pre();
if let Some(v) = self.nimber_from_any_db(&position) {
self.stats.db_cut(v);
return v;
}
self.stats.recursive();
progress_reporter.begin(moves_count);
for result in 0..moves_count {
progress_reporter.progress(result);
debug_assert!(result < 256);
let result = result as u8;
if self.has_nimber_lv(&position, result) {
self.transposition_table.store_nimber(position, result);
self.stats.exact(result);
progress_reporter.end();
return result;
}
}
debug_assert!(moves_count < 256);
let moves_count = moves_count as u8;
self.transposition_table.store_nimber(position, moves_count);
self.stats.exact(moves_count);
progress_reporter.end();
moves_count }
}
impl<G, TT, EDB, SORTER, STATS, DP> Solver<'_, G, TT, EDB, SORTER, STATS>
where G: for<'c> DecomposableGame<'c, DecomposablePosition=DP>,
TT: NimbersProvider<G::Position> + NimbersStorer<G::Position>,
EDB: NimbersProvider<G::Position>,
SORTER: DecomposableGameMoveSorter<G>,
STATS: StatsCollector,
G::Position: Clone {
#[inline(always)]
fn decomposable_has_nimber(&mut self, m: &mut ComponentsInfo, move_components: &Vec<<G as Game>::Position>, nim: u8) -> bool {
while m.len > 1 {
self.stats.pre();
m.nimber ^= self.nimber_of_component_inner(&move_components[m.first + m.len - 1], ());
m.len -= 1;
}
self.has_nimber(&move_components[m.first], nim ^ m.nimber)
}
fn nimber_of_component_inner<PR: ProgressReporter>(&mut self, position: &G::Position, mut progress_reporter: PR) -> u8 {
if let Some(v) = self.nimber_from_tt(&position) {
self.stats.db_cut(v);
return v;
}
let (moves_count, nimbers_to_skip, move_components, mut moves) = self.etc_decomposable(&position);
self.stats.recursive();
progress_reporter.begin(moves_count);
for new_nim in 0..moves_count {
progress_reporter.progress(new_nim);
debug_assert!(new_nim < 256);
let new_nim = new_nim as u8;
if nimbers_to_skip.includes(new_nim) { continue; }
if let Some(index) = moves.iter_mut().position(|m| self.decomposable_has_nimber(m, &move_components, new_nim)) {
SORTER::remove(&mut moves, index); } else { self.transposition_table.store_nimber(position.clone(), new_nim);
self.stats.exact(new_nim);
progress_reporter.end();
return new_nim;
}
}
debug_assert!(moves_count < 256);
let moves_count = moves_count as u8;
self.transposition_table.store_nimber(position.clone(), moves_count);
self.stats.exact(moves_count);
progress_reporter.end();
moves_count }
}
impl<G, TT, EDB, SORTER, STATS, DP> LVDecomposableGameSolver<G> for Solver<'_, G, TT, EDB, SORTER, STATS>
where G: for<'c> DecomposableGame<'c, DecomposablePosition=DP>,
TT: NimbersProvider<G::Position> + NimbersStorer<G::Position>,
EDB: NimbersProvider<G::Position>,
SORTER: DecomposableGameMoveSorter<G>,
STATS: StatsCollector,
G::Position: Clone
{
fn has_nimber_lv(&mut self, position: &G::Position, nim: u8) -> bool {
self.stats.pre();
let moves_count = self.game.moves_count(position);
if moves_count < nim as u16 {
self.stats.unknown();
return false;
}
if let Some(v) = self.nimber_from_tt(&position) { self.stats.db_cut(v);
return v == nim;
}
self.stats.etc();
let mut move_components: Vec::<G::Position> = Vec::with_capacity(moves_count as usize * 2);
let mut moves: Vec::<ComponentsInfo> = Vec::with_capacity(moves_count as usize);
for composed_move in self.game.successors(&position) {
let info = self.decompose(&composed_move, &mut move_components);
if info.len == 0 { if info.nimber == nim { self.stats.unknown();
return false;
}
} else {
moves.push(info);
}
}
self.move_sorter.sort_moves(&self.game, &mut moves, &mut move_components);
self.stats.recursive();
for new_nim in 0..nim {
if nimbers_to_skip.includes(new_nim) { continue; }
if let Some(index) = moves.iter_mut().position(|m| {
self.decomposable_has_nimber(m, &move_components, new_nim)
}) {
SORTER::remove(&mut moves, index); } else { self.transposition_table.store_nimber(position.clone(), new_nim);
self.stats.exact(new_nim);
return false; }
}
if moves_count > nim as u16 && moves.iter_mut().any(|m| self.decomposable_has_nimber(m, &move_components, nim)) {
self.stats.unknown();
return false; }
self.transposition_table.store_nimber(position.clone(), nim);
self.stats.exact(nim);
true
}
fn nimber_of_component_lvb_report_progress<PR: ProgressReporter>(&mut self, position: G::Position, progress_reporter: PR) -> u8 {
self.stats.pre();
if let Some(v) = self.nimber_from_const_db(&position) {
self.stats.db_cut(v);
return v;
}
self.nimber_of_component_inner(&position, progress_reporter)
}
fn nimber_lvb_report_progress<PR: ProgressReporter + Clone>(&mut self, position: <G as DecomposableGame<'_>>::DecomposablePosition, progress_reporter: PR) -> u8 {
let mut result = 0u8;
for component in self.game.decompose(&position) {
result ^= self.nimber_of_component_lvb_report_progress(component, progress_reporter.clone());
}
result
}
}