use crate::{ board::{board::Color, mailbox::Mailbox}, movegen::r#move::Move, }; use super::MAX_HISTORY; // ttmove: -100, mvvlva: [-32, 5], killer:6, quiet[7, ..] pub fn score_move( mailbox: &Mailbox, mv: Move, killer_move: Option, color: Color, history_heuristic: Option<&[[[i32; 64]; 64]; 2]>, tt_move: Option, ) -> i32 { if Some(mv) == tt_move { return -100; } if mv.is_capture() { let aggressor = mailbox.piece_at(mv.src()).unwrap(); if let Some(victim) = mailbox.piece_at(mv.dst()) { return aggressor.0.idx() as i32 - 8 * victim.0.idx() as i32; } return 0; //en passant } if Some(mv) == killer_move { return 6; } history_heuristic.map_or(MAX_HISTORY + 6 + 1, |hh| { -hh[color][mv.src()][mv.dst()] + MAX_HISTORY + 6 + 1 }) } #[cfg(test)] mod tests { use crate::{ board::{fen::from_fen, square::Square}, movegen::r#move::{Move, MoveType}, }; use super::score_move; const FEN: &'static str = "1r2k2r/2P1p2p/2npb1q1/1p3ppP/p3P3/P2B1Q2/1P1PNPP1/R3K2R w KQk - 0 1"; #[test] fn test_score_move() -> Result<(), String> { let game = from_fen(FEN)?; let queen_takes_pawn = Move::new_with_type(Square::F3, Square::F5, MoveType::Capture); let pawn_takes_queen = Move::new_with_type(Square::H5, Square::G6, MoveType::Capture); let castle = Move::new_with_type(Square::E1, Square::C1, MoveType::QueenCastle); let mut moves = vec![castle, queen_takes_pawn, pawn_takes_queen]; moves.sort_unstable_by_key(|mv| { score_move(&game.mailbox, *mv, None, game.current_player(), None, None) }); assert_eq!(moves, vec![pawn_takes_queen, queen_takes_pawn, castle]); moves.sort_unstable_by_key(|mv| { score_move( &game.mailbox, *mv, None, game.current_player(), None, Some(castle), ) }); assert_eq!(moves, vec![castle, pawn_takes_queen, queen_takes_pawn]); Ok(()) } }