1use crate::game::{Game, SimpleGame, DecomposableGame};
2use crate::dbs::{NimbersProvider, NimbersStorer};
3use crate::moves::{ComponentsInfo, SimpleGameMoveSorter, DecomposableGameMoveSorter};
4use crate::nimber_set::NimberSet;
5
6pub mod def;
7pub use self::def::DefSimpleGameSolver as _;
8pub use self::def::DefDecomposableGameSolver as _;
9
10pub mod lvb;
11pub use self::lvb::LVBSimpleGameSolver as _;
12pub use self::lvb::LVBDecomposableGameSolver as _;
13
14pub mod br;
15pub use self::br::BRSimpleGameSolver as _;
16pub use self::br::BRDecomposableGameSolver as _;
17
18pub mod dedicated;
19pub use self::dedicated::{SolverForSimpleGame, SolverForDecomposableGame};
20
21pub mod stats;
22pub use stats::StatsCollector;
23use std::collections::HashMap;
24
25mod outcome;
26
27pub struct Solver<'g, G, TT = HashMap::<<G as Game>::Position, u8>, EDB = (), SORTER = (), STATS = ()>
37 where G: Game,
38 TT: NimbersProvider<G::Position> + NimbersStorer<G::Position>,
39 EDB: NimbersProvider<G::Position>,
40 STATS: StatsCollector
41{
42 pub game: &'g G,
44
45 pub transposition_table: TT,
47
48 pub const_db: EDB,
50
51 pub move_sorter: SORTER,
53
54 pub stats: STATS
56
57 }
59
60impl<'a, G, TT, EDB, SORTER, STATS> Solver<'a, G, TT, EDB, SORTER, STATS>
61 where G: Game,
62 TT: NimbersProvider<G::Position> + NimbersStorer<G::Position>,
63 EDB: NimbersProvider<G::Position>,
64 STATS: StatsCollector
65{
66 #[inline(always)]
67 fn nimber_from_tt(&mut self, p: &G::Position) -> Option<u8> {
68 self.stats.tt_read();
69 self.transposition_table.get_nimber_and_self_organize(p)
70 }
71
72 #[inline(always)]
73 fn nimber_from_const_db(&mut self, p: &G::Position) -> Option<u8> {
74 self.stats.const_db_read();
75 self.const_db.get_nimber_and_self_organize(p)
76 }
77
78 #[inline(always)]
79 fn nimber_from_any_db(&mut self, p: &G::Position) -> Option<u8> {
80 self.nimber_from_const_db(&p).or_else(|| self.nimber_from_tt(&p))
81 }
82
83 pub fn new(game: &'a G, transposition_table: TT, const_db: EDB, move_sorter: SORTER, stats: STATS) -> Self {
84 Self { game, transposition_table, const_db, move_sorter, stats }
85 }
86}
87
88impl<G, TT, EDB, SORTER, STATS> Solver<'_, G, TT, EDB, SORTER, STATS>
89 where G: SimpleGame,
90 TT: NimbersProvider<G::Position> + NimbersStorer<G::Position>,
91 EDB: NimbersProvider<G::Position>,
92 SORTER: SimpleGameMoveSorter<G>,
93 STATS: StatsCollector
94{
95 #[inline(always)]
96 fn etc_simple(&mut self, position: &<G as Game>::Position) -> (u16, G::NimberSet, Vec<<G as Game>::Position>) {
97 self.stats.etc();
98 let moves_count = self.game.moves_count(&position);
99 let mut nimbers_to_skip = G::NimberSet::empty();
100 let mut moves: Vec::<G::Position> = Vec::with_capacity(moves_count as usize);
101 for m in self.game.successors_in_heuristic_ordered(&position) {
102 if let Some(v) = self.nimber_from_any_db(&m) {
103 self.stats.db_skip(v);
104 nimbers_to_skip.append(v);
105 } else {
106 moves.push(m);
107 }
108 }
109 self.move_sorter.sort_moves(&self.game, &mut moves);
110 (moves_count, nimbers_to_skip, moves)
111 }
112}
113
114impl<G, TT, EDB, SORTER, STATS, DP> Solver<'_, G, TT, EDB, SORTER, STATS>
115 where G: DecomposableGame<DecomposablePosition=DP>,
116 TT: NimbersProvider<G::Position> + NimbersStorer<G::Position>,
117 EDB: NimbersProvider<G::Position>,
118 SORTER: DecomposableGameMoveSorter<G>,
119 STATS: StatsCollector
120{
121 #[inline(always)]
122 fn etc_decomposable(&mut self, position: &&<G as Game>::Position) -> (u16, G::NimberSet, Vec<<G as Game>::Position>, Vec<ComponentsInfo>) {
123 self.stats.etc();
124 let moves_count = self.game.moves_count(position);
125 let mut nimbers_to_skip = G::NimberSet::empty();
126 let mut move_components: Vec::<G::Position> = Vec::with_capacity(moves_count as usize * 2);
127 let mut moves: Vec::<ComponentsInfo> = Vec::with_capacity(moves_count as usize);
128 for composed_move in self.game.successors_in_heuristic_ordered(&position) {
129 let info = self.decompose(&composed_move, &mut move_components);
130 if info.len == 0 { nimbers_to_skip.append(info.nimber);
132 } else {
133 moves.push(info);
134 }
135 }
136 self.move_sorter.sort_moves(&self.game, &mut moves, &mut move_components);
137 (moves_count, nimbers_to_skip, move_components, moves)
138 }
139}
140
141
142impl<G, TT, EDB, SORTER, STATS, DP> Solver<'_, G, TT, EDB, SORTER, STATS>
143 where G: DecomposableGame<DecomposablePosition=DP>,
144 TT: NimbersProvider<G::Position> + NimbersStorer<G::Position>,
145 EDB: NimbersProvider<G::Position>,
146 STATS: StatsCollector
147{
148 fn decompose(&mut self, composed_move: &DP, move_components: &mut Vec<<G as Game>::Position>) -> ComponentsInfo {
152 let mut info = ComponentsInfo::new(move_components.len());
153 for c in self.game.decompose(&composed_move) {
154 if let Some(v) = self.nimber_from_any_db(&c) {
155 self.stats.db_skip(v);
156 info.nimber ^= v;
157 } else {
158 move_components.push(c);
159 info.len += 1;
160 }
161 }
162 info
163 }
164
165}