From af7cf2b8168abcfaf0e422e2edede58ca71fd309 Mon Sep 17 00:00:00 2001 From: Ethan Barry Date: Fri, 29 Nov 2024 15:58:50 -0600 Subject: [PATCH 1/2] Clean up evaluation. --- src/gamemanager/evaluation/mod.rs | 8 +++++--- src/gamemanager/legal_moves/search.rs | 29 +++++++++++++-------------- src/main.rs | 3 +-- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/gamemanager/evaluation/mod.rs b/src/gamemanager/evaluation/mod.rs index 3ab2dce..86e7a7e 100644 --- a/src/gamemanager/evaluation/mod.rs +++ b/src/gamemanager/evaluation/mod.rs @@ -20,8 +20,10 @@ impl GameManager { 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 heatmap = heatmaps::Heatmap::default(); + let heatmap = heatmaps::Heatmap::default().rev(); + // 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 * 100 / START_MASS; let position_score = @@ -31,7 +33,7 @@ impl GameManager { } else { // Ditto for white. let mass_score = self.bitboard.piece_mass(Color::White) + movetype_weight(movetype); - let heatmap = heatmaps::Heatmap::default().rev(); + let heatmap = heatmaps::Heatmap::default(); let endgame_weight = mass_score * 100 / START_MASS; @@ -56,7 +58,7 @@ fn movetype_weight(mt: MoveType) -> i32 { NPromotion => Knight as i32, NPromoCapture => Knight as i32 + 50, EPCapture => Pawn as i32, - Capture => 400, + Capture => 100, _ => 0, } } diff --git a/src/gamemanager/legal_moves/search.rs b/src/gamemanager/legal_moves/search.rs index 281a580..51f2371 100644 --- a/src/gamemanager/legal_moves/search.rs +++ b/src/gamemanager/legal_moves/search.rs @@ -32,12 +32,14 @@ pub fn root_negamax(depth: u16, gm: GameManager, tbl: &NoArc) -> (Mov 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 +56,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 gm.evaluate(MoveType::QuietMove); // 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 05ff1ff..6831f85 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,8 +10,7 @@ mod ucimanager; fn main() { let tbl = noarc::NoArc::new(MoveTable::default()); - let gm = - GameManager::from_fen_str("3r3r/pkppqp2/1nN1pbp1/3P4/1p2P3/8/PPPBNPpP/1K1R2R1 b - - 3 6"); + let gm = GameManager::from_fen_str("rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8"); let bestmove = root_negamax(3, gm, &tbl).0; println!("Best move: {}{}", bestmove.1.to_str(), bestmove.2.to_str()) } From 9fd8dc553768cdc075f7d610741d6be4587f7d2d Mon Sep 17 00:00:00 2001 From: Ethan Barry Date: Fri, 29 Nov 2024 17:23:39 -0600 Subject: [PATCH 2/2] Fix heatmaps, i32 truncation issue. --- src/gamemanager/evaluation/heatmaps.rs | 8 ++++---- src/gamemanager/evaluation/mod.rs | 19 +++++++++---------- src/gamemanager/legal_moves/search.rs | 8 ++++++-- src/main.rs | 5 +++-- src/types.rs | 2 +- 5 files changed, 23 insertions(+), 19 deletions(-) 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 86e7a7e..62984a5 100644 --- a/src/gamemanager/evaluation/mod.rs +++ b/src/gamemanager/evaluation/mod.rs @@ -19,28 +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 heatmap = heatmaps::Heatmap::default().rev(); + let mass_score = self.bitboard.piece_mass(Color::Black); + let heatmap = heatmaps::Heatmap::default(); // 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 * 100 / START_MASS; + 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 heatmap = heatmaps::Heatmap::default(); + 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) } } } @@ -57,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 => 100, + Capture => 500, _ => 0, } } diff --git a/src/gamemanager/legal_moves/search.rs b/src/gamemanager/legal_moves/search.rs index 51f2371..6202572 100644 --- a/src/gamemanager/legal_moves/search.rs +++ b/src/gamemanager/legal_moves/search.rs @@ -30,7 +30,11 @@ 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)); + } let best = scored_moves .into_iter() @@ -56,7 +60,7 @@ fn negamax( let moves = gm.legal_moves(tbl); if moves.len() == 0 { - return gm.evaluate(MoveType::QuietMove); // Return value of node. + return i32::MIN + 1; // Return value of node. } let mut score = i32::MIN + 1; diff --git a/src/main.rs b/src/main.rs index 6831f85..42c72f7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,8 +10,9 @@ mod ucimanager; fn main() { let tbl = noarc::NoArc::new(MoveTable::default()); - let gm = GameManager::from_fen_str("rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8"); - let bestmove = root_negamax(3, gm, &tbl).0; + 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()) } diff --git a/src/types.rs b/src/types.rs index a2528a3..4969da0 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,