diff options
author | eug-vs <eugene@eug-vs.xyz> | 2023-02-27 03:41:26 +0300 |
---|---|---|
committer | eug-vs <eugene@eug-vs.xyz> | 2023-02-27 03:41:26 +0300 |
commit | 5e2238ce4ae4ad7bc2d57ee45af866976211e6d3 (patch) | |
tree | 6766d57de41fd52fcc319150dc5e2ea8f2da21c1 | |
parent | a333e9285d55dad06b6507340f1c0416c9c7b6f9 (diff) | |
download | chessnost-5e2238ce4ae4ad7bc2d57ee45af866976211e6d3.tar.gz |
feat: add 3-fold repetition
-rw-r--r-- | src/board/io.rs | 1 | ||||
-rw-r--r-- | src/board/mod.rs | 12 | ||||
-rw-r--r-- | src/grossmeister/UCI.rs | 2 | ||||
-rw-r--r-- | src/grossmeister/search.rs | 11 |
4 files changed, 19 insertions, 7 deletions
diff --git a/src/board/io.rs b/src/board/io.rs index d27b856..15d7744 100644 --- a/src/board/io.rs +++ b/src/board/io.rs @@ -97,6 +97,7 @@ impl IO for Board { castling_rights: [[true; 2]; 2], // TODO: actualy parse from FEN ep_target: None, // TODO: parse from FEN clock: Clock::default(), + positions: Vec::new(), hash: 0, zobrist_seed: Board::seed(), }; diff --git a/src/board/mod.rs b/src/board/mod.rs index 95d470a..50aa1b9 100644 --- a/src/board/mod.rs +++ b/src/board/mod.rs @@ -15,7 +15,7 @@ pub enum CastlingSide { /// Chess board is an main interface to the internal game state. /// Board defines rules of the game and manages players actions. -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct Board { pub ply: u16, pub piece_sets: [Bitboard; 12], @@ -26,12 +26,16 @@ pub struct Board { pub clock: Clock, + /// List of all positions to determine repetitions + pub positions: Vec<u64>, + // Computed values pub occupancy: Bitboard, /// Zobrist hash of the current position pub hash: u64, zobrist_seed: ZobristSeed, + pub attacks: Attacks, } @@ -227,6 +231,7 @@ impl Board { self.ply += 1; self.zobrist_toggle_color(); + self.positions.push(self.hash); captured_piece } @@ -320,6 +325,7 @@ impl Board { self.castling_rights = previous_castling_rights; self.hash = previous_hash; self.ply -= 1; + self.positions.pop(); } pub fn is_square_attacked(&self, square: Square, attacker_color: Color) -> bool { @@ -388,7 +394,7 @@ mod tests { fn make_move() { let fen = String::from("q1b2k2/5p1p/4p1pb/pPPp4/3N4/3nPB2/P2QKnR1/1R6 w - - 0 25"); let mut board = Board::from_FEN(fen); - let initial_board = board; + let initial_board = board.clone(); board.print(); let black_move = Move { source: Square::F7, target: Square::F5, kind: MoveKind::Quiet }; @@ -429,7 +435,7 @@ mod tests { fn unmake_move() { let fen = String::from("q1b2k2/5p1p/4p1pb/pPPp4/3N4/3nPB2/P2QKnR1/1R6 w - - 0 25"); let mut board = Board::from_FEN(fen); - let initial_board = board; + let initial_board = board.clone(); let mov = Move { source: Square::D2, target: Square::A5, kind: MoveKind::Capture }; diff --git a/src/grossmeister/UCI.rs b/src/grossmeister/UCI.rs index 034b73b..3132e72 100644 --- a/src/grossmeister/UCI.rs +++ b/src/grossmeister/UCI.rs @@ -59,7 +59,7 @@ impl Grossmeister { .find(|m| { let promo_matches = match input_move.kind { MoveKind::Promotion(piece) => match m.kind { - MoveKind::Promotion(another_piece) => piece == another_piece, + MoveKind::Promotion(another_piece) => piece.without_color() == another_piece.without_color(), _ => false }, _ => true, diff --git a/src/grossmeister/search.rs b/src/grossmeister/search.rs index 5c03887..43423e4 100644 --- a/src/grossmeister/search.rs +++ b/src/grossmeister/search.rs @@ -45,6 +45,11 @@ impl Grossmeister { } } + if self.board.positions.iter().filter(|p| **p == self.board.hash).count() >= 3 { + // Draw by repetition + return (0.0, principal_variation); + } + if depth_left == 0 { return (self.quiscence(alpha, beta), principal_variation); } @@ -447,7 +452,7 @@ mod tests { let fen = String::from("2kr1b1r/pp1npppp/2p1bn2/7q/5B2/2NB1Q1P/PPP1N1P1/2KR3R w - - 0 1"); let board = Board::from_FEN(fen); let mut gm = Grossmeister::new(board); - let (score, pv) = gm.iterative_deepening(8, Duration::from_secs(15), true); + let (score, pv) = gm.iterative_deepening(8); assert_eq!(score, VALUE_WIN); assert_eq!(pv, vec![ @@ -464,7 +469,7 @@ mod tests { board.ply += 1; // TODO: remove me when FEN parsing includes side to move let mut gm = Grossmeister::new(board); - let (_, pv) = gm.iterative_deepening(6, Duration::from_secs(60), true); + let (_, pv) = gm.iterative_deepening(6); assert_eq!( pv[0], Move { source: Square::F5, target: Square::H4, kind: MoveKind::Quiet }, @@ -478,7 +483,7 @@ mod tests { let board = Board::from_FEN(fen); let mut gm = Grossmeister::new(board); - let (_, pv) = gm.iterative_deepening(5, Duration::from_secs(60), true); + let (_, pv) = gm.iterative_deepening(5); assert_eq!( pv[0], Move { source: Square::C2, target: Square::C3, kind: MoveKind::Quiet }, |