1use crate::{Solver, SolverEvent};
2use crate::{Game, BreakingMoveIterator};
3use crate::rcsplit::RCSplit;
4use crate::stats::NimberStats;
5use crate::BitSet;
6
7pub struct RC2Solver<const DYNAMIC_REBUILD: bool = true, S = ()> {
8 game: Game,
9 breaking: [Vec<u8>; 2], nimbers: Vec<u16>,
11 nimber_num: NimberStats,
12 split: [RCSplit; 2],
13 pub stats: S
14}
15
16impl<const DYNAMIC_REBUILD: bool, S: SolverEvent> Solver for RC2Solver<DYNAMIC_REBUILD, S> {
17 type Stats = S;
18
19 #[inline] fn stats(&self) -> &Self::Stats { &self.stats }
20 #[inline] fn nimbers(&self) -> &[u16] { &self.nimbers }
21 #[inline] fn game(&self) -> &Game { &self.game }
22 #[inline] fn capacity(&self) -> usize { self.nimbers.capacity() }
23
24 #[inline] fn with_stats(game: Game, stats: S) -> Self {
25 let breaking = Self::split_breaking_moves(&game);
26 Self { game, breaking, nimbers: Vec::new(), nimber_num: Default::default(), stats, split: [RCSplit::new(0), RCSplit::new(1)] }
27 }
28
29 #[inline] fn with_capacity_stats(game: Game, capacity: usize, stats: S) -> Self {
30 let breaking = Self::split_breaking_moves(&game);
31 Self { game, breaking, nimbers: Vec::with_capacity(capacity), nimber_num: Default::default(), stats, split: [RCSplit::new(0), RCSplit::new(1)] }
32 }
33
34 fn print_nimber_stat_to(&self, f: &mut dyn std::io::Write) -> std::io::Result<()> {
35 writeln!(f, "{:+}", self.nimber_num)?;
36 if !self.breaking[0].is_empty() { writeln!(f, "{:.0}", self.split[0])?; }
37 if !self.breaking[1].is_empty() { writeln!(f, "{:.1}", self.split[1])?; }
38 Ok(())
39 }
40}
41
42impl<const DYNAMIC_REBUILD: bool, S> RC2Solver<DYNAMIC_REBUILD, S> {
43 fn split_breaking_moves(game: &Game) -> [Vec<u8>; 2] {
44 let mut result = [Vec::<u8>::new(), Vec::<u8>::new()];
45 for m in game.breaking.iter().copied() {
46 result[(m & 1) as usize].push(m);
47 }
48 result
49 }
50}
51
52#[inline(always)] fn in_r<const D: u16>(breaking: &[Vec<u8>; 2], split: &mut [RCSplit; 2], nim_pos: u16) -> bool {
53 if breaking[D as usize].is_empty() {
54 false } else {
56 split[D as usize].in_r(nim_pos, D)
57 }
58}
59
60impl<const DYNAMIC_REBUILD: bool, S: SolverEvent> Iterator for RC2Solver<DYNAMIC_REBUILD, S> {
61 type Item = u16;
62
63 fn next(&mut self) -> Option<Self::Item> {
64 let mut option_nimbers = [0u64; 1<<(16-6)]; let n = self.nimbers.len();
66 self.game.consider_taking(&self.nimbers, &mut option_nimbers, &mut self.stats);
67 for d in [0, 1] {
68 for b in &self.breaking[d] {
69 let b = *b as usize;
70 if b+1 >= n { break }
71 let after_take = n - b;
72 for i in &self.split[d].r_positions {
73 if *i >= after_take { break; }
74 option_nimbers.add_nimber(self.nimbers[*i] ^ self.nimbers[after_take-i]);
75 self.stats.break_option();
76 }
77 }
78 }
79 let nd = n as u16 & 1;
80 let mut result = (option_nimbers.mex() << 1) | nd;
81 let mut to_check = [
82 in_r::<0>(&self.breaking, &mut self.split, result),
83 in_r::<1>(&self.breaking, &mut self.split, result)
84 ];
85 let mut moves = [
86 BreakingMoveIterator::for_slice(n, &self.breaking[0]).fuse(),
87 BreakingMoveIterator::for_slice(n, &self.breaking[1]).fuse()
88 ];
89 while to_check[0] || to_check[1] {
90 for d in [0, 1] {
91 while to_check[d] {
92 if let Some((a, b)) = moves[d].next() {
93 let option_nimber = self.nimbers[a] ^ self.nimbers[b];
94 option_nimbers.add_nimber(option_nimber);
95 if (result>>1) == option_nimber {
96 result = (option_nimbers.mex() << 1) | nd;
97 to_check = [
98 in_r::<0>(&self.breaking, &mut self.split, result),
99 in_r::<1>(&self.breaking, &mut self.split, result)
100 ];
101 }
102 self.stats.break_option();
103 } else { to_check[d] = false; }
104 }
105 }
106 }
107 self.nimber_num.count(result);
108 self.nimbers.push(result>>1);
109 for d in [0, 1] {
110 if self.breaking[d].is_empty() { continue; }
111 if DYNAMIC_REBUILD {
112 if self.split[d].r.contain_nimber(result) {
113 if n != 0 { self.split[d].r_positions.push(n); }
114 if self.split[d].should_rebuild_d(result, &self.nimber_num) {
115 self.split[d].update_d(&self.nimber_num, &self.nimbers, d as u16, &mut self.stats);
116 }
118 } else {
120 self.split[d].add_to_c(result);
121 }
122 } else {
123 if n.is_power_of_two() {
124 self.split[d].rebuild_d(&self.nimber_num, &self.nimbers, d as u16, &mut self.stats);
125 } else if self.split[d].r.contain_nimber(result) {
126 if n != 0 { self.split[d].r_positions.push(n); }
127 } else {
128 self.split[d].add_to_c(result);
129 }
130 }
131 }
132 Some(result>>1)
134 }
135}