Skip to content

Commit 1e44bda

Browse files
87flowersSaphereye
andauthored
Refactor keys (#1043)
STC non-reg Elo | 0.93 +- 1.72 (95%) SPRT | 8.0+0.08s Threads=1 Hash=16MB LLR | 3.03 (-2.25, 2.89) [-2.75, 0.25] Games | N: 39288 W: 10042 L: 9937 D: 19309 Penta | [140, 4309, 10663, 4370, 162] https://recklesschess.space/test/14978/ Bench: 3466720 Co-Authored-By: Adarsh Das <adarshdas950@gmail.com>
1 parent 2024e35 commit 1e44bda

4 files changed

Lines changed: 73 additions & 36 deletions

File tree

src/board.rs

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use crate::{
55
},
66
setwise::{bishop_attacks_setwise, knight_attacks_setwise, pawn_attacks_setwise, rook_attacks_setwise},
77
types::{
8-
Bitboard, Castling, CastlingKind, Color, File, Move, PAWN_HOME_RANK, PROMO_RANK, Piece, PieceType, Square,
9-
ZOBRIST,
8+
Bitboard, Castling, CastlingKind, Color, File, Keys, Move, PAWN_HOME_RANK, PROMO_RANK, Piece, PieceType,
9+
Square, ZOBRIST,
1010
},
1111
};
1212

@@ -24,9 +24,7 @@ mod see;
2424
/// Implements the `Copy` trait for efficient memory duplication via bitwise copying.
2525
#[derive(Copy, Clone, Default)]
2626
struct InternalState {
27-
key: u64,
28-
pawn_key: u64,
29-
non_pawn_keys: [u64; Color::NUM],
27+
keys: Keys,
3028
en_passant: Square,
3129
castling: Castling,
3230
halfmove_clock: u8,
@@ -83,15 +81,15 @@ impl Board {
8381
// To mitigate Graph History Interaction (GHI) problems, the hash key is changed
8482
// every 8 plies to distinguish between positions that would otherwise appear
8583
// identical to the transposition table.
86-
self.state.key ^ ZOBRIST.halfmove_clock[self.halfmove_clock_bucket()]
84+
self.state.keys.full() ^ ZOBRIST.halfmove_clock[self.halfmove_clock_bucket()]
8785
}
8886

8987
pub const fn pawn_key(&self) -> u64 {
90-
self.state.pawn_key
88+
self.state.keys.pawn()
9189
}
9290

9391
pub const fn non_pawn_key(&self, color: Color) -> u64 {
94-
self.state.non_pawn_keys[color as usize]
92+
self.state.keys.non_pawn(color)
9593
}
9694

9795
pub const fn pinned(&self, color: Color) -> Bitboard {
@@ -222,15 +220,7 @@ impl Board {
222220
}
223221

224222
pub fn update_hash(&mut self, piece: Piece, square: Square) {
225-
let key = ZOBRIST.pieces[piece][square];
226-
227-
self.state.key ^= key;
228-
229-
if piece.piece_type() == PieceType::Pawn {
230-
self.state.pawn_key ^= key;
231-
} else {
232-
self.state.non_pawn_keys[piece.color()] ^= key;
233-
}
223+
self.state.keys.toggle(piece, square);
234224
}
235225

236226
/// Checks for a material draw
@@ -293,23 +283,23 @@ impl Board {
293283
return false;
294284
}
295285

296-
let current_key = self.state.key;
286+
let current_key = self.state.keys.full();
297287
let stack = &self.state_stack;
298288
let len = stack.len();
299289

300290
let mut index = len - 1;
301-
let mut other = current_key ^ stack[index].key ^ ZOBRIST.side;
291+
let mut other = current_key ^ stack[index].keys.full() ^ ZOBRIST.side;
302292

303293
for compared_ply in (3..=half_moves).step_by(2) {
304294
index -= 1;
305-
other ^= stack[index].key ^ stack[index - 1].key ^ ZOBRIST.side;
295+
other ^= stack[index].keys.full() ^ stack[index - 1].keys.full() ^ ZOBRIST.side;
306296
index -= 1;
307297

308298
if other != 0 {
309299
continue;
310300
}
311301

312-
let diff = current_key ^ stack[index].key;
302+
let diff = current_key ^ stack[index].keys.full();
313303
let mut cuckoo_index = h1(diff);
314304

315305
if cuckoo(cuckoo_index) != diff {
@@ -493,9 +483,7 @@ impl Board {
493483
}
494484

495485
pub fn update_hash_keys(&mut self) {
496-
self.state.key = 0;
497-
self.state.pawn_key = 0;
498-
self.state.non_pawn_keys = [0; Color::NUM];
486+
self.state.keys = Keys::default();
499487

500488
for piece in 0..Piece::NUM {
501489
let piece = Piece::from_index(piece);
@@ -506,14 +494,14 @@ impl Board {
506494
}
507495

508496
if self.en_passant() != Square::None {
509-
self.state.key ^= ZOBRIST.en_passant[self.en_passant()];
497+
self.state.keys.toggle_en_passant(self.en_passant());
510498
}
511499

512500
if self.side_to_move() == Color::White {
513-
self.state.key ^= ZOBRIST.side;
501+
self.state.keys.toggle_side();
514502
}
515503

516-
self.state.key ^= ZOBRIST.castling[self.state.castling];
504+
self.state.keys.toggle_castling(self.state.castling);
517505
}
518506

519507
fn is_en_passant_valid(&self) -> bool {
@@ -546,7 +534,7 @@ impl Board {
546534
return;
547535
}
548536

549-
self.state.key ^= ZOBRIST.en_passant[self.en_passant()];
537+
self.state.keys.toggle_en_passant(self.en_passant());
550538
self.state.en_passant = Square::None;
551539
}
552540

src/board/makemove.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
use super::{Board, BoardObserver};
2-
use crate::types::{Move, MoveKind, Piece, PieceType, Square, ZOBRIST};
2+
use crate::types::{Move, MoveKind, Piece, PieceType, Square};
33

44
impl Board {
55
pub fn make_null_move(&mut self) {
66
self.side_to_move = !self.side_to_move;
77
self.state_stack.push(self.state);
88

9-
self.state.key ^= ZOBRIST.side ^ ZOBRIST.castling[self.state.castling];
9+
self.state.keys.toggle_side();
10+
self.state.keys.toggle_castling(self.state.castling);
1011
self.state.plies_from_null = 0;
1112
self.state.repetition = 0;
1213
self.state.captured = None;
1314

1415
self.update_threats();
1516

1617
if self.en_passant() != Square::None {
17-
self.state.key ^= ZOBRIST.en_passant[self.en_passant()];
18+
self.state.keys.toggle_en_passant(self.en_passant());
1819
self.state.en_passant = Square::None;
1920
}
2021
}
@@ -35,10 +36,11 @@ impl Board {
3536

3637
self.state_stack.push(self.state);
3738

38-
self.state.key ^= ZOBRIST.castling[self.state.castling] ^ ZOBRIST.side;
39+
self.state.keys.toggle_side();
40+
self.state.keys.toggle_castling(self.state.castling);
3941

4042
if self.en_passant() != Square::None {
41-
self.state.key ^= ZOBRIST.en_passant[self.en_passant()];
43+
self.state.keys.toggle_en_passant(self.en_passant());
4244
self.state.en_passant = Square::None;
4345
}
4446

@@ -90,7 +92,7 @@ impl Board {
9092
match mv.kind() {
9193
MoveKind::DoublePush => {
9294
self.state.en_passant = to ^ 8;
93-
self.state.key ^= ZOBRIST.en_passant[self.en_passant()];
95+
self.state.keys.toggle_en_passant(self.en_passant());
9496
}
9597
MoveKind::EnPassant => {
9698
let captured = self.remove_piece(to ^ 8);
@@ -120,7 +122,7 @@ impl Board {
120122
self.side_to_move = !self.side_to_move;
121123

122124
self.state.castling.raw &= self.castling_rights[from] & self.castling_rights[to];
123-
self.state.key ^= ZOBRIST.castling[self.state.castling];
125+
self.state.keys.toggle_castling(self.state.castling);
124126

125127
self.update_threats();
126128
self.update_en_passant();
@@ -138,7 +140,7 @@ impl Board {
138140

139141
let stp = &self.state_stack[idx as usize];
140142

141-
if stp.key == self.state.key {
143+
if stp.keys.full() == self.state.keys.full() {
142144
self.state.repetition = if stp.repetition != 0 { -(i as i32) } else { i as i32 };
143145
break;
144146
}

src/types/keys.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use crate::types::{Castling, Color, Piece, PieceType, Square, ZOBRIST};
2+
3+
#[derive(Clone, Copy, Default)]
4+
pub struct Keys {
5+
pub full: u64,
6+
pub pawn: u64,
7+
pub non_pawn: [u64; Color::NUM],
8+
}
9+
10+
impl Keys {
11+
pub fn full(&self) -> u64 {
12+
self.full
13+
}
14+
15+
pub const fn pawn(&self) -> u64 {
16+
self.pawn
17+
}
18+
19+
pub const fn non_pawn(&self, color: Color) -> u64 {
20+
self.non_pawn[color as usize]
21+
}
22+
23+
pub fn toggle(&mut self, piece: Piece, sq: Square) {
24+
let piece_key = ZOBRIST.pieces[piece][sq];
25+
26+
self.full ^= piece_key;
27+
28+
match piece.piece_type() {
29+
PieceType::Pawn => self.pawn ^= piece_key,
30+
_ => self.non_pawn[piece.color()] ^= piece_key,
31+
}
32+
}
33+
34+
pub fn toggle_side(&mut self) {
35+
self.full ^= ZOBRIST.side;
36+
}
37+
38+
pub fn toggle_castling(&mut self, castling: Castling) {
39+
self.full ^= ZOBRIST.castling[castling];
40+
}
41+
42+
pub fn toggle_en_passant(&mut self, en_passant: Square) {
43+
self.full ^= ZOBRIST.en_passant[en_passant];
44+
}
45+
}

src/types/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pub mod arrayvec;
22
pub mod bitboard;
33
pub mod castling;
44
pub mod color;
5+
pub mod keys;
56
pub mod movelist;
67
pub mod moves;
78
pub mod piece;
@@ -13,6 +14,7 @@ pub use arrayvec::*;
1314
pub use bitboard::*;
1415
pub use castling::*;
1516
pub use color::*;
17+
pub use keys::*;
1618
pub use movelist::*;
1719
pub use moves::*;
1820
pub use piece::*;

0 commit comments

Comments
 (0)