diff options
author | eug-vs <eugene@eug-vs.xyz> | 2023-01-23 18:15:06 +0300 |
---|---|---|
committer | eug-vs <eugene@eug-vs.xyz> | 2023-01-23 18:15:06 +0300 |
commit | 36c8c6bd84513fe2a8c9956b842baaee510b25c0 (patch) | |
tree | 53ff3a819627aeedfe856eee506b44cc7618f244 /src/board.rs | |
parent | aa80421ebb89c5d776d9b981a4145b58b73f01db (diff) | |
download | chessnost-36c8c6bd84513fe2a8c9956b842baaee510b25c0.tar.gz |
feat: add basic negamax implementation
Diffstat (limited to 'src/board.rs')
-rw-r--r-- | src/board.rs | 61 |
1 files changed, 60 insertions, 1 deletions
diff --git a/src/board.rs b/src/board.rs index 7f35e91..3343702 100644 --- a/src/board.rs +++ b/src/board.rs @@ -1,4 +1,4 @@ -use crate::{bitboard::{Bitboard, serialize_bitboard, bitscan}, moves::{Move, MoveKind}, attacks::Attacks, square::Square}; +use crate::{bitboard::{Bitboard, serialize_bitboard, bitscan, pop_count}, moves::{Move, MoveKind}, attacks::Attacks, square::Square}; pub enum CastlingSide { King, @@ -114,6 +114,11 @@ impl Board { Self::from_FEN(default_fen) } + /// Color to move at this ply + fn color(&self) -> Color { + Color::from(self.ply as u8 % 2) + } + fn update_occupancy(&mut self) { self.occupancy = 0; // TODO: reduce @@ -606,6 +611,49 @@ impl Board { let square = bitscan(king_bb); self.is_square_attacked(square, color.flip()) } + + fn evaluate(&self) -> f32 { + let mut eval = 0f32; + let pieces = self.pieces_by_color(self.color()); + eval += pop_count(pieces[PieceType::Pawn as usize]) as f32; + eval += pop_count(pieces[PieceType::Bishop as usize]) as f32 * 3.; + eval += pop_count(pieces[PieceType::Knight as usize]) as f32 * 3.; + eval += pop_count(pieces[PieceType::Rook as usize]) as f32 * 4.5; + eval += pop_count(pieces[PieceType::Queen as usize]) as f32 * 9.; + eval + } + + fn negamax_search(&mut self, mut alpha: f32, beta: f32, depth_left: u8) -> f32 { + let color = Color::from(self.ply as u8 % 2); + + self.print(); + + if depth_left == 0 { + return self.evaluate(); + } + let moves = self.generate_pseudolegal_moves(color); + + for mov in moves { + let ep_target_before = self.ep_target.clone(); + let castling_rights_before = self.castling_rights.clone(); + let captured_piece = self.make_move(mov); + + if !self.is_king_in_check(color) { + let evaluation = -self.negamax_search(-beta, -alpha, depth_left - 1); + self.unmake_move(mov, captured_piece, ep_target_before, castling_rights_before); + + if (evaluation >= beta) { + return beta; // Fail-hard beta-cutoff + } + if (evaluation > alpha) { + alpha = evaluation + } + } else { + self.unmake_move(mov, captured_piece, ep_target_before, castling_rights_before); + } + } + alpha + } } @@ -634,6 +682,8 @@ impl Color { #[cfg(test)] mod tests { + use std::f32::INFINITY; + use super::*; use crate::{bitboard::{pop_count, bitscan, print}, square::Square}; @@ -777,4 +827,13 @@ mod tests { assert_eq!(board.is_square_attacked(Square::E4, Color::White), false); assert_eq!(board.is_square_attacked(Square::B6, Color::Black), true); } + + #[test] + fn negamax_search() { + let fen = String::from("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - "); + let mut board = Board::from_FEN(fen); + + let eval = board.negamax_search(-INFINITY, INFINITY, 4); + println!("{}", eval); + } } |