diff --git a/src/gamemanager/evaluation/heatmaps.rs b/src/gamemanager/evaluation/heatmaps.rs index bf6b86a..fb204b5 100644 --- a/src/gamemanager/evaluation/heatmaps.rs +++ b/src/gamemanager/evaluation/heatmaps.rs @@ -10,8 +10,8 @@ pub struct Heatmap { } impl Default for Heatmap { - /// Returns the heatmaps for white. - /// Use .rev() to get the heatmaps for black. + /// Returns the heatmaps for black. + /// Use .rev() to get the heatmaps for white. fn default() -> Self { let pawns_start = [ 0, 0, 0, 0, 0, 0, 0, 0, 50, 50, 50, 50, 50, 50, 50, 50, 10, 10, 20, 30, 30, 20, 10, 10, @@ -79,8 +79,8 @@ impl Default for Heatmap { } impl Heatmap { - /// Returns the heatmap for black, if the provided - /// heatmap is for white, and vice versa. + /// Returns the heatmap for white, if the provided + /// heatmap is for black, and vice versa. pub fn rev(&self) -> Self { Self { pawns_start: reverse_array(self.pawns_start), diff --git a/src/gamemanager/evaluation/mod.rs b/src/gamemanager/evaluation/mod.rs index 3ab2dce..62984a5 100644 --- a/src/gamemanager/evaluation/mod.rs +++ b/src/gamemanager/evaluation/mod.rs @@ -19,26 +19,28 @@ impl GameManager { pub fn evaluate(&self, movetype: MoveType) -> i32 { if self.white_to_move { // Evaluate for black; better or worse after its move? - let mass_score = self.bitboard.piece_mass(Color::Black) + movetype_weight(movetype); + let mass_score = self.bitboard.piece_mass(Color::Black); let heatmap = heatmaps::Heatmap::default(); - let endgame_weight = mass_score * 100 / START_MASS; + // endgame_weight shows how close we are to the endgame. The more pieces our side has, the further + // it is from the end of the game, and the fewer, the closer to the end of the game. + let endgame_weight = (mass_score / START_MASS) * 100; let position_score = eval_heatmaps(Color::Black, self.bitboard, heatmap, endgame_weight); - position_score + mass_score + position_score + mass_score + movetype_weight(movetype) } else { // Ditto for white. - let mass_score = self.bitboard.piece_mass(Color::White) + movetype_weight(movetype); + let mass_score = self.bitboard.piece_mass(Color::White); let heatmap = heatmaps::Heatmap::default().rev(); - let endgame_weight = mass_score * 100 / START_MASS; + let endgame_weight = (mass_score / START_MASS) * 100; let position_score = eval_heatmaps(Color::White, self.bitboard, heatmap, endgame_weight); - position_score + mass_score + position_score + mass_score + movetype_weight(movetype) } } } @@ -55,8 +57,7 @@ fn movetype_weight(mt: MoveType) -> i32 { BPromoCapture => Bishop as i32 + 50, NPromotion => Knight as i32, NPromoCapture => Knight as i32 + 50, - EPCapture => Pawn as i32, - Capture => 400, + Capture => 500, _ => 0, } } diff --git a/src/gamemanager/legal_moves/search.rs b/src/gamemanager/legal_moves/search.rs index 281a580..6202572 100644 --- a/src/gamemanager/legal_moves/search.rs +++ b/src/gamemanager/legal_moves/search.rs @@ -30,14 +30,20 @@ pub fn root_negamax(depth: u16, gm: GameManager, tbl: &NoArc) -> (Mov .map(|(s, movetuple)| (s, (movetuple.0, movetuple.1))) .collect(); - scored_moves.sort_by(|a, b| a.0.cmp(&b.0)); + if depth % 2 == 0 { + scored_moves.sort_by(|a, b| a.0.cmp(&b.0)); + } else { + scored_moves.sort_by(|a, b| a.0.cmp(&b.0)); + } - // Little bit of debugging code. - let _ = scored_moves - .iter() - .for_each(|m| println!("{}: {}{}", m.0, m.1 .0 .1.to_str(), m.1 .0 .2.to_str())); + let best = scored_moves + .into_iter() + .inspect(|m| println!("{}: {}{}", m.0, m.1 .0 .1.to_str(), m.1 .0 .2.to_str())) + .last() + .expect("Should be a move here!"); - scored_moves.pop().expect("There'll be a move!").1 + println!("Best score: {}", best.0); + best.1 } fn negamax( @@ -54,22 +60,19 @@ fn negamax( let moves = gm.legal_moves(tbl); if moves.len() == 0 { - return i32::MIN + 1; // It's a pretty bad outcome to have no moves, - // but stalemates shouldn't count so hard against us. + return i32::MIN + 1; // Return value of node. } + let mut score = i32::MIN + 1; for mv in moves { // Call negamax and negate it's return value. Enemy's alpha is our -beta & v.v. - let score = -negamax(depth - 1, -beta, -alpha, mv.3, &mv.4, tbl); - - if score >= beta { - return beta; - } - if score > alpha { - alpha = score; + score = score.max(-negamax(depth - 1, -beta, -alpha, mv.3, &mv.4, tbl)); + alpha = alpha.max(score); + if alpha >= beta { + break; } } - alpha + score } } diff --git a/src/main.rs b/src/main.rs index f544808..24488e5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,16 @@ mod ucimanager; mod enginemanager; fn main() { + + let tbl = noarc::NoArc::new(MoveTable::default()); + + let gm = + GameManager::from_fen_str("rn1b1k1r/p4ppp/1pp5/8/2B5/3n4/PPP1N1PP/RNBQ1K1R w - - 0 11"); + let bestmove = root_negamax(4, gm, &tbl).0; + println!("Best move: {}{}", bestmove.1.to_str(), bestmove.2.to_str()) + ucimanager::communicate(); + } #[cfg(test)] diff --git a/src/types.rs b/src/types.rs index 2d8caec..dbb5626 100644 --- a/src/types.rs +++ b/src/types.rs @@ -5,7 +5,7 @@ use std::fmt::Display; #[derive(Debug, Clone, Eq, Hash, PartialEq)] pub enum PieceType { King, - Queen = 900, + Queen = 1000, Rook = 500, Bishop = 320, Knight = 300,