Skip to content

Commit 179f223

Browse files
Merge pull request #103 from DeveloperPaul123/fix/output-correct-pv
bench: 2517656
2 parents d6e1a20 + d458dae commit 179f223

File tree

5 files changed

+289
-48
lines changed

5 files changed

+289
-48
lines changed

.vscode/settings.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,10 @@
5050
"Tsouchlos",
5151
"zobrist"
5252
],
53-
"makefile.configureOnOpen": false
53+
"makefile.configureOnOpen": false,
54+
"files.readonlyInclude": {
55+
"**/.cargo/registry/src/**/*.rs": true,
56+
"**/.cargo/git/checkouts/**/*.rs": true,
57+
"**/lib/rustlib/src/rust/library/**/*.rs": true,
58+
},
5459
}

engine/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ mod lmr;
1414
mod move_order;
1515
pub(crate) mod node_types;
1616
pub mod phased_score;
17+
pub(crate) mod principle_variation;
1718
pub mod score;
1819
pub mod search;
1920
pub mod search_thread;

engine/src/principle_variation.rs

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
use core::panic;
2+
3+
use arrayvec::ArrayVec;
4+
use chess::{definitions::MAX_MOVES, moves::Move};
5+
6+
/// Represents the [Principle Variation](https://www.chessprogramming.org/Principal_Variation) during a search.
7+
#[derive(Debug)]
8+
pub(crate) struct PrincipleVariation {
9+
data: ArrayVec<Move, MAX_MOVES>,
10+
}
11+
12+
impl Default for PrincipleVariation {
13+
fn default() -> Self {
14+
Self::new()
15+
}
16+
}
17+
18+
impl PrincipleVariation {
19+
/// Create a new, empty ['PrincipleVariation'].
20+
pub(crate) fn new() -> Self {
21+
Self {
22+
data: ArrayVec::new(),
23+
}
24+
}
25+
26+
/// Push a move to the ['PrincipleVariation'].
27+
///
28+
/// # Arguments:
29+
///
30+
/// - m: The new move to add to the principle variation.
31+
///
32+
/// # Returns:
33+
///
34+
/// Empty Result<> on success or an error if the underlying ArrayVec
35+
/// is full before trying to push.
36+
#[allow(clippy::panic)]
37+
pub(crate) fn push(&mut self, m: Move) {
38+
self.data.try_push(m).unwrap_or_else(|err| {
39+
panic!(
40+
"Error extending PV of size {} when adding {}\n {err}",
41+
self.data.len(),
42+
m
43+
);
44+
})
45+
}
46+
47+
/// Extend the current [PrincipleVariation] with the given move and another principle variation.
48+
///
49+
/// This will clear the current PV and append the given move and [PrincipleVariation].
50+
///
51+
/// # Arguments:
52+
///
53+
/// - m: The new move to add to the principle variation.
54+
/// - pv: The principle variation to append to the current variation.
55+
#[inline(always)]
56+
#[allow(clippy::panic)]
57+
pub(crate) fn extend(&mut self, m: Move, pv: &Self) {
58+
self.clear();
59+
self.push(m);
60+
self.data
61+
.try_extend_from_slice(pv.data.as_slice())
62+
.unwrap_or_else(|err| {
63+
panic!(
64+
"Error extending PV of size {} when adding {} and {:?}\n {err}",
65+
self.data.len(),
66+
m,
67+
pv
68+
);
69+
})
70+
}
71+
72+
/// Clear the principle variation.
73+
pub(crate) fn clear(&mut self) {
74+
self.data.clear();
75+
}
76+
77+
/// Returns an iterator to the underlying data of the [PrincipleVariation].
78+
pub(crate) fn iter(&self) -> impl Iterator<Item = &Move> {
79+
self.data.iter()
80+
}
81+
}
82+
83+
#[cfg(test)]
84+
mod tests {
85+
use chess::{definitions::Squares, moves::MoveDescriptor, pieces::Piece, square::Square};
86+
87+
use super::*;
88+
89+
fn make_moves() -> (Move, Move) {
90+
let move1 = Move::new(
91+
&Square::from_square_index(Squares::E2),
92+
&Square::from_square_index(Squares::E4),
93+
MoveDescriptor::PawnTwoUp,
94+
Piece::Pawn,
95+
None,
96+
None,
97+
);
98+
99+
let move2 = Move::new(
100+
&Square::from_square_index(Squares::E7),
101+
&Square::from_square_index(Squares::E5),
102+
MoveDescriptor::PawnTwoUp,
103+
Piece::Pawn,
104+
None,
105+
None,
106+
);
107+
108+
(move1, move2)
109+
}
110+
111+
#[test]
112+
fn add_moves_to_principle_variation() {
113+
let mut pv = PrincipleVariation::new();
114+
115+
let (move1, move2) = make_moves();
116+
117+
// Push moves to the principle variation
118+
pv.push(move1);
119+
pv.push(move2);
120+
121+
// Check that the moves are in the principle variation
122+
assert_eq!(pv.data.len(), 2);
123+
}
124+
125+
#[test]
126+
fn extend_principle_variation() {
127+
let mut pv = PrincipleVariation::new();
128+
129+
let (move1, move2) = make_moves();
130+
131+
// Push the first move to the principle variation
132+
pv.push(move1);
133+
134+
// Create a new principle variation to extend from
135+
let mut pv2 = PrincipleVariation::new();
136+
pv2.push(move2);
137+
138+
// Extend the original principle variation with the new one
139+
pv.extend(move1, &pv2);
140+
141+
// Check that the moves are in the principle variation
142+
assert_eq!(pv.data.len(), 1 + pv2.data.len());
143+
}
144+
145+
#[test]
146+
#[should_panic(expected = "Error extending PV")]
147+
fn extending_or_pushing_move_past_max_size_panics() {
148+
let (move1, move2) = make_moves();
149+
let mut pv = PrincipleVariation::new();
150+
151+
// Fill the principle variation to its maximum size
152+
for _ in 0..MAX_MOVES {
153+
pv.push(move1);
154+
}
155+
156+
// Attempt to push another move, which should fail
157+
pv.push(move2);
158+
159+
// reset
160+
pv = PrincipleVariation::new();
161+
let mut pv2 = PrincipleVariation::new();
162+
163+
// Fill the principle variation to its maximum size
164+
for _ in 0..MAX_MOVES - 10 {
165+
pv.push(move1);
166+
}
167+
168+
for _ in 0..10 {
169+
pv2.push(move2);
170+
}
171+
172+
// Attempt to extend the principle variation with another one that would exceed the max size
173+
pv.extend(move2, &pv2);
174+
}
175+
}

0 commit comments

Comments
 (0)