Skip to content

Commit 0e20284

Browse files
committed
better threefold prevention
1 parent 123df4e commit 0e20284

File tree

7 files changed

+80
-9
lines changed

7 files changed

+80
-9
lines changed

src/engine/evaluation/material.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,17 @@ pub fn material(board: &Board, side: Color, interp: Interp) -> Value {
6060
let side_board = board.color_combined(side);
6161
for (idx, piece) in MAT_PIECE_TYPES.iter().enumerate() {
6262
let count = board.pieces(*piece).bitand(side_board).popcnt();
63+
// let blocked = if side == board.side_to_move() {
64+
// board.pieces(*piece).bitand(board.pinned()).popcnt()
65+
// } else {
66+
// board
67+
// .null_move()
68+
// .map(|b| b.pieces(*piece).bitand(b.pinned()).popcnt())
69+
// // .unwrap_or(0)
70+
// .unwrap_or(board.color_combined(!side).popcnt())
71+
// };
72+
// let adj = count.saturating_add(count).saturating_sub(blocked).checked_shr(1).
73+
// unwrap_or_default();
6374
value += (INITIAL_VALUES[idx] * Value::from(count)) * interp.0;
6475
value += (MIDGAME_VALUES[idx] * Value::from(count)) * interp.1;
6576
value += (ENDGAME_VALUES[idx] * Value::from(count)) * interp.2;

src/engine/evaluation/position.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
//! evaluating the positions of the pieces on the board
22
use std::ops::BitAnd;
33

4+
use chess::BitBoard;
45
use chess::Board;
56
use chess::Color;
7+
use chess::Piece;
68
use chess::Square;
79

810
use crate::evaluation::Interp;
@@ -11,6 +13,11 @@ use crate::evaluation::bitboards::MG_PESTO_TABLE;
1113
use crate::evaluation::bitboards::POS_PIECE_TYPES;
1214
use crate::setup::values::Value;
1315

16+
/// bitboard of dark squares
17+
const DARK_SQUARES: BitBoard = BitBoard(0xAA55AA55AA55AA55);
18+
/// bitboard of light squares
19+
const LIGHT_SQUARES: BitBoard = BitBoard(0x55AA55AA55AA55AA);
20+
1421
/// returns the benefit this side has from its pieces' positions
1522
pub fn piece_position_benefit_for_side(pos: &Board, color: Color, interp: Interp) -> Value {
1623
let mut value = Value::ZERO;
@@ -48,6 +55,23 @@ pub fn sq_pi(sq: Square, color: Color) -> (usize, usize) {
4855
(rank, file)
4956
}
5057

58+
/// check how much are my bishops blocked by other pieces.
59+
///
60+
/// issue: engine sacks bishops to minimise penalty
61+
#[allow(dead_code)]
62+
pub fn bishop_penalty(pos: &Board, side: Color) -> Value {
63+
let bishop_squares = pos.pieces(Piece::Bishop) & pos.color_combined(side);
64+
let mut penalty = Value::ZERO;
65+
66+
let dark_bishops = bishop_squares.bitand(DARK_SQUARES);
67+
let light_bishops = bishop_squares.bitand(LIGHT_SQUARES);
68+
69+
penalty += Value::from((pos.combined() & DARK_SQUARES).popcnt() * dark_bishops.popcnt());
70+
penalty += Value::from((pos.combined() & LIGHT_SQUARES).popcnt() * light_bishops.popcnt());
71+
72+
penalty
73+
}
74+
5175
#[cfg(test)]
5276
#[path = "tests/positions.rs"]
5377
mod tests;

src/engine/position.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ impl Position {
2727

2828
/// check whether this position, if added to the engine history, will cause
2929
/// a draw by threefold repetition
30-
pub fn causes_threefold(&self, history: &[Position]) -> bool {
30+
pub fn causes_threefold(&self, history: &[u64]) -> bool {
3131
history
3232
.iter()
33-
.filter(|p| p.chessboard.eq(&self.chessboard))
33+
.filter(|p| **p == self.chessboard.get_hash())
3434
.count()
3535
>= 2
3636
}

src/engine/search/main_search.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,12 @@ impl Engine {
5656

5757
let tt = self.table.get();
5858

59-
let engine_history = self.history.make_contiguous().to_vec();
59+
let engine_history = self
60+
.history
61+
.make_contiguous()
62+
.iter_mut()
63+
.map(|p| p.chessboard.get_hash())
64+
.collect::<Vec<_>>();
6065

6166
thread::spawn(move || {
6267
let mut best_move: Option<ChessMove> = None;
@@ -75,6 +80,14 @@ impl Engine {
7580

7681
let initial_options = SearchOptions {
7782
extensions: Depth::ZERO,
83+
history: [
84+
*engine_history.first().unwrap_or(&0),
85+
*engine_history.get(1).unwrap_or(&0),
86+
*engine_history.get(2).unwrap_or(&0),
87+
*engine_history.get(3).unwrap_or(&0),
88+
*engine_history.get(4).unwrap_or(&0),
89+
*engine_history.get(5).unwrap_or(&0),
90+
],
7891
};
7992

8093
// SAFETY: if it fails it's due to poison,

src/engine/search/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ pub struct SearchOptions {
109109
/// how many times have we already extended the search? this is necessary to
110110
/// ensure the recursion terminates, and to prevent stack overflow.
111111
pub extensions: Depth,
112+
113+
/// previously played position that would cause draw by threefold repetition
114+
pub history: [u64; 6],
112115
}
113116

114117
/// wrapper around [`SEARCH_UNTIL`]

src/engine/search/negamax.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,28 @@ pub fn negamax(
106106

107107
optlog!(search;trace;"ng: {pos}, td: {to_depth:?}, a: {alpha:?}, b: {beta:?}");
108108

109+
let current_hash = pos.chessboard.get_hash();
110+
if search_options
111+
.history
112+
.iter()
113+
.filter(|x| **x == current_hash)
114+
.count()
115+
>= 2
116+
{
117+
// threefold repetition
118+
let ev = evaluate(&pos, true);
119+
return SearchResult {
120+
pv: vec![],
121+
next_position_value: ev,
122+
nodes_searched: 1,
123+
tb_hits: 0,
124+
depth: ONE_PLY,
125+
};
126+
}
127+
109128
/* source: https://en.wikipedia.org/wiki/Negamax */
110129
let alpha_orig = alpha;
111130
if opts.use_tt {
112-
let current_hash = pos.chessboard.get_hash(); // change
113131
if let Ok(Some(tt_entry)) = table.read().map(|l| l.get(current_hash)) {
114132
if tt_entry.is_valid() {
115133
if tt_entry.depth() >= to_depth {
@@ -161,11 +179,13 @@ pub fn negamax(
161179
// if theres 3 moves or less, search +1 level deeper
162180
};
163181

182+
search_options.history.rotate_left(1);
183+
search_options.history[5] = current_hash;
164184
search_options = SearchOptions {
165185
extensions: search_options
166186
.extensions
167187
.max(search_options.extensions + next_depth + 1 - to_depth),
168-
// ..search_options
188+
history: search_options.history,
169189
};
170190

171191
let mut best = None;

src/engine/search/tests/negatest.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ use crate::util::short_benches;
2424
fn startpos_is_positive() {
2525
let pos = Board::default();
2626
SEARCHING.store(true, Ordering::Relaxed);
27+
let val = ng_test(pos, Depth(4), Value::MIN, Value::MAX, Opts::new()).unwrap();
2728
assert!(
28-
ng_test(pos, Depth(4), Value::MIN, Value::MAX, Opts::new())
29-
.unwrap()
30-
.next_position_value
31-
> Value::ZERO
29+
val.next_position_value > Value::ZERO,
30+
"startpos was {}",
31+
val.next_position_value
3232
);
3333
}
3434

0 commit comments

Comments
 (0)