pub struct OpeningBookDatabase { /* private fields */ }Implementations§
Source§impl OpeningBookDatabase
impl OpeningBookDatabase
Sourcepub fn open(config: &OpeningBookConfig) -> SqlResult<Self>
pub fn open(config: &OpeningBookConfig) -> SqlResult<Self>
Examples found in repository?
100fn main() {
101 let args = parse_args();
102
103 let started = Instant::now();
104 let mut states = enumerate_depth4();
105 println!(
106 "enumerated {} canonical nonterminal depth-4 states in {:.2}s",
107 states.len(),
108 started.elapsed().as_secs_f64()
109 );
110 if args.sample > 0 && args.sample < states.len() {
111 use rand::prelude::*;
112 let mut rng = StdRng::seed_from_u64(args.seed);
113 states.shuffle(&mut rng);
114 states.truncate(args.sample);
115 states.sort_by_key(|(bb, _)| bb.to_le_bytes());
116 println!(
117 "sampled {} of {} states (seed={})",
118 states.len(),
119 10946,
120 args.seed
121 );
122 } else if args.limit > 0 {
123 states.truncate(args.limit);
124 println!("limited to {} states for this run", states.len());
125 }
126
127 let book = OpeningBookDatabase::open(&OpeningBookConfig {
128 database_path: args.db.clone(),
129 ..Default::default()
130 })
131 .expect("open book");
132
133 let mut rows: Vec<serde_json::Value> = Vec::with_capacity(states.len());
134 let mut solved = 0usize;
135 let mut cutoff = 0usize;
136 let solve_started = Instant::now();
137
138 for (i, (bb, mult)) in states.iter().enumerate() {
139 let t0 = Instant::now();
140 let reference = solve_position_with_book(bb, args.budget_s, Some(&book));
141 let elapsed = t0.elapsed().as_secs_f64();
142 println!(
143 " [{}/{}] {} solved={} elapsed={:.3}s",
144 i + 1,
145 states.len(),
146 State::new(*bb).to_qfen(),
147 reference.is_some(),
148 elapsed
149 );
150
151 match &reference {
152 Some(r) => {
153 solved += 1;
154 rows.push(serde_json::json!({
155 "qfen": State::new(*bb).to_qfen(),
156 "multiplicity": mult,
157 "value": r["value"],
158 "nodes": r["nodes"],
159 "solve_time_s": elapsed,
160 "solver": r["solver"],
161 }));
162 }
163 None => {
164 cutoff += 1;
165 rows.push(serde_json::json!({
166 "qfen": State::new(*bb).to_qfen(),
167 "multiplicity": mult,
168 "value": null,
169 "nodes": null,
170 "solve_time_s": elapsed,
171 "solver": null,
172 }));
173 }
174 }
175
176 if (i + 1) % 25 == 0 || i + 1 == states.len() {
177 println!(
178 "progress: {}/{} solved={} cutoff={} elapsed_total={:.1}s",
179 i + 1,
180 states.len(),
181 solved,
182 cutoff,
183 solve_started.elapsed().as_secs_f64()
184 );
185 // Flush partial results after every progress line so a killed
186 // run still leaves a readable, if incomplete, artifact — the
187 // SQLite book itself is already durable per-row regardless.
188 let partial = serde_json::json!({
189 "budget_s": args.budget_s,
190 "total_canonical_depth4_states": states.len(),
191 "processed": i + 1,
192 "solved": solved,
193 "cutoff": cutoff,
194 "positions": rows,
195 });
196 std::fs::write(&args.out, serde_json::to_string_pretty(&partial).unwrap())
197 .expect("write partial output");
198 }
199 }
200
201 println!(
202 "done: {} solved, {} cutoff, total solve wall time {:.1}s -> {}",
203 solved,
204 cutoff,
205 solve_started.elapsed().as_secs_f64(),
206 args.out
207 );
208}pub fn add_position( &self, state: &State, evaluation: f64, visit_count: i64, win_count_p0: i64, win_count_p1: i64, draw_count: i64, best_moves: &[(i32, i32)], depth: i32, is_terminal: TerminalStatus, symmetry_count: i32, ) -> SqlResult<()>
Sourcepub fn add_solved_position(
&self,
state: &State,
game_value: i32,
optimal_moves: &[(i32, i32)],
) -> SqlResult<bool>
pub fn add_solved_position( &self, state: &State, game_value: i32, optimal_moves: &[(i32, i32)], ) -> SqlResult<bool>
Upsert an exactly-solved position: evaluation is game_value as
f64, is_terminal stays Interior (the position itself is not
terminal — its game value is exactly known), depth is pieces
placed (derived from state.bb), and best_moves records every
optimal move (not just a top-5 slice, unlike Self::add_position)
as (shape, position) pairs in the given order.
Only canonical representatives are stored. The optimal moves
are expressed in state’s own board orientation, but the row is
keyed by the canonical key shared by up to eight symmetric
orientations; storing a non-representative orientation would let a
later lookup on the representative serve moves that are wrong
(possibly illegal) for that board. If state is not its own
canonical representative (canonical_payload() != bb.to_le_bytes()),
nothing is written and Ok(false) is returned; Ok(true) means
the row was upserted. Translating moves across orientations via
the symmetry transform is a documented follow-up that would lift
this restriction.
The position row and its best-move rows are written in one
transaction, so a mid-way failure can never leave a solved row
with partial best_moves.
Visit/win/draw counters and symmetry_count are not meaningful for
a solved reference and are stored as 0.
pub fn get_position(&self, state: &State) -> SqlResult<Option<OpeningBookEntry>>
pub fn query_by_depth( &self, depth: i32, limit: i64, ) -> SqlResult<Vec<OpeningBookEntry>>
pub fn add_edges(&self, edges: &[(&[u8], &[u8])]) -> SqlResult<()>
pub fn get_children(&self, canonical_key: &[u8]) -> SqlResult<Vec<Vec<u8>>>
pub fn get_parents(&self, canonical_key: &[u8]) -> SqlResult<Vec<Vec<u8>>>
pub fn get_edge_count(&self) -> SqlResult<i64>
pub fn total_positions(&self) -> SqlResult<i64>
pub fn max_depth(&self) -> SqlResult<Option<i32>>
pub fn positions_by_depth(&self) -> SqlResult<Vec<(i32, i64)>>
pub fn db_path(&self) -> &str
pub fn file_size(&self) -> u64
Trait Implementations§
Source§impl Drop for OpeningBookDatabase
impl Drop for OpeningBookDatabase
Auto Trait Implementations§
impl !Freeze for OpeningBookDatabase
impl !RefUnwindSafe for OpeningBookDatabase
impl !Sync for OpeningBookDatabase
impl !UnwindSafe for OpeningBookDatabase
impl Send for OpeningBookDatabase
impl Unpin for OpeningBookDatabase
impl UnsafeUnpin for OpeningBookDatabase
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more