-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathkiller_moves.rs
More file actions
92 lines (79 loc) · 3.1 KB
/
killer_moves.rs
File metadata and controls
92 lines (79 loc) · 3.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//! Killer move storage using thread-local storage for parallel search.
use thread_local::ThreadLocal;
type KillerMovePair = [Option<Box<dyn std::any::Any + Send + Sync>>; 2];
type KillerMovesVec = Vec<KillerMovePair>;
type KillerMovesStorage = std::cell::RefCell<Option<KillerMovesVec>>;
static KILLER_MOVES: ThreadLocal<KillerMovesStorage> = ThreadLocal::new();
/// Creates a new killer move storage vector.
fn create_killer_vec(max_ply: usize) -> KillerMovesVec {
(0..=max_ply).map(|_| [None, None]).collect()
}
/// Manages killer moves using thread-local storage for parallel search.
///
/// Killer moves are quiet moves that caused beta cutoffs at the same ply in
/// other branches of the search tree. Storing them per-ply improves move
/// ordering by prioritizing moves likely to cause cutoffs.
pub(crate) struct KillerMovesManager {
max_depth: usize,
}
impl KillerMovesManager {
pub fn new(max_depth: u8) -> Self {
Self {
max_depth: max_depth as usize,
}
}
fn ensure_storage(&self) {
let storage = KILLER_MOVES.get_or(|| std::cell::RefCell::new(None));
let mut storage_ref = storage.borrow_mut();
let needs_init = storage_ref.is_none()
|| storage_ref
.as_ref()
.is_some_and(|killers| killers.len() <= self.max_depth);
if needs_init {
*storage_ref = Some(create_killer_vec(self.max_depth));
}
}
pub fn store<M: Clone + Send + Sync + 'static>(&self, ply: u8, killer: M) {
let ply = ply as usize;
self.ensure_storage();
let storage = KILLER_MOVES.get().expect("storage should be initialized");
if let Some(ref mut killers) = *storage.borrow_mut() {
if ply < killers.len() {
let old_first = killers[ply][0].take();
killers[ply][1] = old_first;
killers[ply][0] = Some(Box::new(killer));
}
}
}
pub fn get<M: Clone + 'static>(&self, ply: u8) -> [Option<M>; 2] {
let ply = ply as usize;
self.ensure_storage();
let storage = KILLER_MOVES.get().expect("storage should be initialized");
if let Some(ref killers) = *storage.borrow() {
if ply < killers.len() {
let mut result = [None, None];
for (i, stored) in killers[ply].iter().enumerate() {
if let Some(boxed) = stored {
if let Some(killer) = boxed.downcast_ref::<M>() {
result[i] = Some(killer.clone());
}
}
}
return result;
}
}
[None, None]
}
pub fn clear(&self) {
if let Some(storage) = KILLER_MOVES.get() {
if let Some(ref mut killers) = *storage.borrow_mut() {
for killer in killers.iter_mut() {
*killer = [
None::<Box<dyn std::any::Any + Send + Sync>>,
None::<Box<dyn std::any::Any + Send + Sync>>,
];
}
}
}
}
}