From 29d69b5ab1952cb8f59d06cdfa911ba6138a2d3e Mon Sep 17 00:00:00 2001 From: stefiosif Date: Sun, 19 Jan 2025 20:15:23 +0200 Subject: [PATCH] Add repetition detection --- src/board/game.rs | 27 +++++++++++++++++++++++++++ src/board/history.rs | 9 +++++++++ src/search/negamax.rs | 4 ++++ 3 files changed, 40 insertions(+) diff --git a/src/board/game.rs b/src/board/game.rs index 19d1253..1b48370 100644 --- a/src/board/game.rs +++ b/src/board/game.rs @@ -244,6 +244,14 @@ impl Game { } } } + + pub fn in_repetition(&self) -> bool { + if self.board.state.halfmove_clock < 4 { + return false; + } + + self.history.in_repetition(self.hash) + } } impl Default for Game { @@ -431,4 +439,23 @@ mod tests { Ok(()) } + + #[test] + fn test_in_repetition() -> Result<(), String> { + let mut game = from_fen(FEN)?; + + game.make_move(&Move::new(Square::F3, Square::E3)); + game.make_move(&Move::new(Square::F7, Square::G7)); + game.make_move(&Move::new(Square::E3, Square::F3)); + game.make_move(&Move::new(Square::G7, Square::F7)); + game.make_move(&Move::new(Square::F3, Square::E3)); + + assert!(game.in_repetition()); + + game.make_move(&Move::new(Square::H7, Square::H6)); + + assert!(!game.in_repetition()); + + Ok(()) + } } diff --git a/src/board/history.rs b/src/board/history.rs index 895cfc0..33eb58d 100644 --- a/src/board/history.rs +++ b/src/board/history.rs @@ -27,6 +27,15 @@ impl History { pub fn pop_move_parameters(&mut self) -> Option { self.move_parameters.pop() } + + pub fn in_repetition(&self, hash: ZobristHash) -> bool { + self.move_parameters + .iter() + .rev() + .skip(1) + .step_by(2) + .any(|mp| mp.zobrist_hash.expect("State without hash") == hash) + } } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/src/search/negamax.rs b/src/search/negamax.rs index f57c9a8..2b4ca52 100644 --- a/src/search/negamax.rs +++ b/src/search/negamax.rs @@ -24,6 +24,10 @@ pub fn negamax( bail!("Time is up! In Negamax"); } + if plies != 0 && game.in_repetition() { + return Ok(0); + } + if depth == 0 { let q_score = quiescence(game, alpha, beta, time_info).map_err(|e| anyhow!("{e}"))?; return Ok(q_score);