diff --git a/src/board/fen.rs b/src/board/fen.rs index a4c1d6f..c60d30f 100644 --- a/src/board/fen.rs +++ b/src/board/fen.rs @@ -2,7 +2,7 @@ use crate::board::board::{Board, Color, PieceType}; use crate::board::game::Game; use crate::board::state::{Castle, State}; use crate::search::transposition_table::TranspositionTable; -use crate::search::MAX_TT_SIZE; +use crate::search::{MAX_DEPTH, MAX_TT_SIZE}; use String as FenError; pub fn from_fen(fen: &str) -> Result { @@ -37,6 +37,7 @@ pub fn from_fen(fen: &str) -> Result { mailbox, hash, tt: TranspositionTable::new(MAX_TT_SIZE), + killer: [None; MAX_DEPTH as usize], }) } diff --git a/src/board/game.rs b/src/board/game.rs index 5b00dfe..1e62b04 100644 --- a/src/board/game.rs +++ b/src/board/game.rs @@ -1,7 +1,7 @@ use crate::{ board::fen::from_fen, movegen::r#move::{Move, MoveType}, - search::{transposition_table::TranspositionTable, MAX_TT_SIZE}, + search::{transposition_table::TranspositionTable, MAX_DEPTH, MAX_TT_SIZE}, }; use String as FenError; @@ -29,6 +29,7 @@ pub struct Game { pub mailbox: Mailbox, pub hash: ZobristHash, pub tt: TranspositionTable, + pub killer: [Option; MAX_DEPTH as usize], } impl Game { @@ -39,6 +40,7 @@ impl Game { mailbox: Mailbox::from_board(&Board::startpos()), hash: zobrist_keys().calculate_hash(&Board::startpos()), tt: TranspositionTable::new(MAX_TT_SIZE), + killer: [None; MAX_DEPTH as usize], } } diff --git a/src/movegen/move.rs b/src/movegen/move.rs index 4f93d5d..a02219b 100644 --- a/src/movegen/move.rs +++ b/src/movegen/move.rs @@ -173,6 +173,13 @@ impl Move { pub fn parse_into_str(&self) -> String { format!("{self:?}") } + + pub const fn is_capture(&self) -> bool { + matches!( + self.move_type, + MoveType::Capture | MoveType::PromotionCapture(_) + ) + } } #[cfg(test)] diff --git a/src/search/move_ordering.rs b/src/search/move_ordering.rs index 4534aff..37bb646 100644 --- a/src/search/move_ordering.rs +++ b/src/search/move_ordering.rs @@ -1,10 +1,19 @@ use crate::{board::mailbox::Mailbox, movegen::r#move::Move}; -pub fn score_move(mailbox: &Mailbox, mv: Move, tt_move: Option) -> i32 { +pub fn score_move( + mailbox: &Mailbox, + mv: Move, + killer_move: Option, + tt_move: Option, +) -> i32 { if Some(mv) == tt_move { return -100; } + if Some(mv) == killer_move { + return -90; + } + let aggressor = mailbox.piece_at(mv.src).expect("No aggressor found."); mailbox.piece_at(mv.dst).map_or(100, |victim| { aggressor.0.idx() as i32 - (victim.0.idx() * 8) as i32 @@ -30,11 +39,11 @@ mod tests { let castle = Move::with_type(Square::E1, Square::C1, MoveType::Castle); let mut moves = vec![castle, queen_takes_pawn, pawn_takes_queen]; - moves.sort_unstable_by_key(|mv| score_move(&game.mailbox, *mv, None)); + moves.sort_unstable_by_key(|mv| score_move(&game.mailbox, *mv, None, None)); assert_eq!(moves, vec![pawn_takes_queen, queen_takes_pawn, castle]); - moves.sort_unstable_by_key(|mv| score_move(&game.mailbox, *mv, Some(castle))); + moves.sort_unstable_by_key(|mv| score_move(&game.mailbox, *mv, None, Some(castle))); assert_eq!(moves, vec![castle, pawn_takes_queen, queen_takes_pawn]); diff --git a/src/search/negamax.rs b/src/search/negamax.rs index a2a17d0..2e331b5 100644 --- a/src/search/negamax.rs +++ b/src/search/negamax.rs @@ -53,7 +53,12 @@ pub fn negamax( } moves.sort_unstable_by_key(|mv| { - score_move(&game.mailbox, *mv, tt_entry.and_then(|entry| entry.mv)) + score_move( + &game.mailbox, + *mv, + game.killer[plies as usize], + tt_entry.and_then(|entry| entry.mv), + ) }); for mv in moves { @@ -88,6 +93,9 @@ pub fn negamax( } if score >= beta { + if !mv.is_capture() { + game.killer[plies as usize] = Some(mv); + } break; } } diff --git a/src/search/quiescence.rs b/src/search/quiescence.rs index 49de54c..ba79512 100644 --- a/src/search/quiescence.rs +++ b/src/search/quiescence.rs @@ -42,7 +42,12 @@ pub fn quiescence( } moves.sort_unstable_by_key(|mv| { - score_move(&game.mailbox, *mv, tt_entry.and_then(|entry| entry.mv)) + score_move( + &game.mailbox, + *mv, + None, + tt_entry.and_then(|entry| entry.mv), + ) }); for mv in moves {