c4_e5_chess/engine/
pvs.rs

1use super::constants::MIN_INT;
2use super::{constants::*, history::History, move_gen::MoveGenPrime, store::Store};
3use crate::eval::{evaluation::Evaluation, simple::Simple};
4use crate::misc::types::*;
5use cozy_chess::{Board, GameStatus, Move};
6use std::sync::{
7    atomic::{AtomicBool, Ordering},
8    Arc,
9};
10
11/// A principal variant search.
12pub struct Pvs {
13    pub history: History,
14    pub node_count: u64,
15    pub store: Store,
16}
17
18impl Pvs {
19    /// Constructor
20    pub fn new() -> Self {
21        Self {
22            history: History::new(),
23            node_count: 0,
24            store: Store::new(),
25        }
26    }
27
28    /// Execute the search given a board and parameters Alpha and Beta
29    pub fn execute(
30        &mut self,
31        board: &Board,
32        depth: Depth,
33        mut alpha: MoveScore,
34        beta: MoveScore,
35        playing: &Arc<AtomicBool>,
36        _capture: bool,
37    ) -> MoveScore {
38        let mut best_move: Option<Move> = None;
39        let mut best_value: MoveScore = MIN_INT;
40
41        if !playing.load(Ordering::Relaxed) {
42            return 0;
43        }
44
45        if board.status() != GameStatus::Ongoing {
46            if board.status() == GameStatus::Won {
47                return -MATE - i32::from(depth);
48            }
49            return 0;
50        }
51
52        if self.history.get(board) > 2 {
53            return 0;
54        }
55
56        if depth < 1 {
57            self.node_count += 1;
58            return Simple::evaluate(board);
59        }
60
61        let children: Vec<AnnotatedMove> = match self.store.get(depth, board) {
62            Some((_, v, true)) => return v,
63            Some((mv, _, false)) => board.get_legal_sorted(Some(mv)),
64            None => board.get_legal_sorted(None),
65        };
66
67        for (i, child) in children.iter().enumerate() {
68            let mut b1 = board.clone();
69            b1.play_unchecked(child.mv);
70            self.history.inc(&b1);
71
72            let value = if i == 0 {
73                -self.execute(&b1, depth - 1, -beta, -alpha, playing, child.cp)
74            } else {
75                let mut value =
76                    -self.execute(&b1, depth - 1, -alpha - 1, -alpha, playing, child.cp);
77                if value > alpha && value < beta {
78                    value = -self.execute(&b1, depth - 1, -beta, -value, playing, child.cp);
79                }
80                value
81            };
82
83            self.history.dec(&b1);
84
85            if value > best_value {
86                best_value = value;
87                best_move = Some(child.mv);
88            }
89
90            if best_value >= beta {
91                break;
92            }
93
94            if best_value > alpha {
95                alpha = best_value;
96            }
97        }
98
99        if let Some(bm) = best_move {
100            self.store.put(depth - 1, best_value, board, &bm);
101        }
102        best_value
103    }
104}
105
106impl Default for Pvs {
107    fn default() -> Self {
108        Self::new()
109    }
110}