Skip to main content

solve_position_with_book

Function solve_position_with_book 

Source
pub fn solve_position_with_book(
    bb: &Bitboard,
    budget_s: f64,
    book: Option<&OpeningBookDatabase>,
) -> Option<Value>
Expand description

Like solve_position, but first probes book (when given) for a stored solved reference at bb’s canonical key, short-circuiting the minimax solve on a hit. On a fresh solve, the result is written back through book (best-effort — a write failure is silently ignored, the solve itself already succeeded and is returned regardless).

See crate::bench::book_export for the orientation caveat: both the lookup and the write-back apply only when bb is its own canonical representative — the stored moves are in that one orientation and cannot be translated across symmetries yet.

Examples found in repository?
examples/depth4_survey.rs (line 140)
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}