pub mod beam;
pub mod bounds;
#[cfg(not(target_arch = "wasm32"))]
pub mod checkpoint;
pub mod nrpa;
pub mod symmetry;
pub mod systematic;
use crate::game::moves::Move;
use std::sync::{
atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering},
Arc, RwLock,
};
use std::time::Duration;
use web_time::Instant;
#[derive(Debug)]
pub struct SearchState {
pub best_score: AtomicU32,
pub best_sequence: RwLock<Vec<Move>>,
pub nodes_explored: AtomicU64,
pub running: AtomicBool,
pub paused: AtomicBool,
pub checkpoint_requested: AtomicBool,
pub exhausted: AtomicBool,
pub records: RwLock<Vec<(u32, Duration)>>,
start_time: RwLock<Option<Instant>>,
}
impl SearchState {
pub fn new() -> Arc<Self> {
Arc::new(Self {
best_score: AtomicU32::new(0),
best_sequence: RwLock::new(Vec::new()),
nodes_explored: AtomicU64::new(0),
running: AtomicBool::new(false),
paused: AtomicBool::new(false),
checkpoint_requested: AtomicBool::new(false),
exhausted: AtomicBool::new(false),
records: RwLock::new(Vec::new()),
start_time: RwLock::new(None),
})
}
pub fn reset(&self) {
self.best_score.store(0, Ordering::Relaxed);
self.nodes_explored.store(0, Ordering::Relaxed);
self.exhausted.store(false, Ordering::Relaxed);
*self.best_sequence.write().unwrap() = Vec::new();
*self.records.write().unwrap() = Vec::new();
*self.start_time.write().unwrap() = Some(Instant::now());
}
pub fn wait_if_paused(&self) {
while self.paused.load(Ordering::Relaxed) && self.running.load(Ordering::Relaxed) {
#[cfg(not(target_arch = "wasm32"))]
std::thread::sleep(Duration::from_millis(50));
#[cfg(target_arch = "wasm32")]
std::hint::spin_loop();
}
}
pub fn record_best(&self, score: u32, history: Vec<Move>) {
let prev = self.best_score.fetch_max(score, Ordering::Relaxed);
if score > prev {
*self.best_sequence.write().unwrap() = history;
let elapsed = self
.start_time
.read()
.unwrap()
.map(|t| t.elapsed())
.unwrap_or_default();
let mut recs = self.records.write().unwrap();
if recs.last().map(|(s, _)| *s != score).unwrap_or(true) {
recs.push((score, elapsed));
}
}
}
}