diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/board/engine.rs | 152 | ||||
| -rw-r--r-- | src/board/mod.rs (renamed from src/board.rs) | 141 | 
2 files changed, 153 insertions, 140 deletions
| diff --git a/src/board/engine.rs b/src/board/engine.rs new file mode 100644 index 0000000..c8b174f --- /dev/null +++ b/src/board/engine.rs @@ -0,0 +1,152 @@ +use crate::{bitboard::pop_count, board::*}; + +impl Board { +    pub fn perft(&mut self, depth: u8, print: bool) -> (u64, u64, u64, u64, u64) { +        if depth == 0 { +            return (1, 0, 0, 0, 0) // This a leaf, exactly one node +        } +        let color = self.color_to_move(); + +        let moves = self.generate_pseudolegal_moves(color); + +        if print { +            println!("Running perft for depth {}. Color to move is {:?}\n{} moves available", depth, color, moves.len()); +            println!("{} moves available", moves.len()); +        } + +        let mut total = 0; +        let mut captures = 0; +        let mut checks = 0; +        let mut castles = 0; +        let mut en_passants = 0; + +        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); +            // King can not be in check after our own move +            if !self.is_king_in_check(color) { +                if depth == 1 { +                    match mov.kind { +                        MoveKind::Capture => { +                            captures += 1; +                        } +                        MoveKind::EnPassant => { +                            en_passants += 1; +                            captures += 1; +                        } +                        MoveKind::Castle => { +                            castles += 1; +                        } +                        _ => {} +                    } +                    if self.is_king_in_check(color.flip()) { +                        checks += 1; +                    } +                } + +                if print { +                    println!("{:?}", mov); +                    self.print(); +                } +                let (children_total, children_tactical, children_checks, children_castles, children_ep) = self.perft(depth - 1, print); +                total += children_total; +                captures += children_tactical; +                checks += children_checks; +                castles += children_castles; +                en_passants += children_ep; + +            } +            self.unmake_move(mov, captured_piece, ep_target_before, castling_rights_before); +        } + +        if print { +            println!("Found {} nodes in this subtree (depth {})", total, depth); +        } + +        (total, captures, checks, castles, en_passants) +    } +    pub 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 +    } + +    pub 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 +    } + +} + + +#[cfg(test)] +mod tests { +    use std::f32::INFINITY; + +    use crate::board::Board; + +    #[test] +    fn perft() { +        let mut board = Board::new(); + +        assert_eq!(board.perft(0, false), (1, 0, 0, 0, 0)); +        assert_eq!(board.perft(1, false), (20, 0, 0, 0, 0)); +        assert_eq!(board.perft(2, false), (400, 0, 0, 0, 0)); +        assert_eq!(board.perft(3, false), (8902, 34, 12, 0, 0)); +        assert_eq!(board.perft(4, false), (197281, 1576, 469, 0, 0)); +        // assert_eq!(board.perft(5, false), (4865609, 82719, 27351, 0, 258)); +        // assert_eq!(board.perft(6, false), (119060324, 2812008, 809099, 0, 5248)); +    } + +    #[test] +    fn position_perft() { +        let fen = String::from("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - "); +        let mut board = Board::from_FEN(fen); +        assert_eq!(board.perft(0, false), (1, 0, 0, 0, 0)); +        assert_eq!(board.perft(1, false), (48, 8, 0, 2, 0)); +        assert_eq!(board.perft(2, false), (2039, 351, 3, 91, 1)); +        assert_eq!(board.perft(3, false), (97862, 17102, 993, 3162, 45)); +    } + +    #[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); +    } +} diff --git a/src/board.rs b/src/board/mod.rs index 9ff81b1..10d0a73 100644 --- a/src/board.rs +++ b/src/board/mod.rs @@ -1,4 +1,5 @@  use crate::{bitboard::{Bitboard, serialize_bitboard, bitscan, pop_count}, moves::{Move, MoveKind}, attacks::Attacks, square::Square}; +mod engine;  pub enum CastlingSide {      King, @@ -501,72 +502,6 @@ impl Board {          self.ply -= 1;      } -    pub fn perft(&mut self, depth: u8, print: bool) -> (u64, u64, u64, u64, u64) { -        if depth == 0 { -            return (1, 0, 0, 0, 0) // This a leaf, exactly one node -        } -        let color = self.color_to_move(); - -        let moves = self.generate_pseudolegal_moves(color); - -        if print { -            println!("Running perft for depth {}. Color to move is {:?}\n{} moves available", depth, color, moves.len()); -            println!("{} moves available", moves.len()); -        } - -        let mut total = 0; -        let mut captures = 0; -        let mut checks = 0; -        let mut castles = 0; -        let mut en_passants = 0; - -        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); -            // King can not be in check after our own move -            if !self.is_king_in_check(color) { -                if depth == 1 { -                    match mov.kind { -                        MoveKind::Capture => { -                            captures += 1; -                        } -                        MoveKind::EnPassant => { -                            en_passants += 1; -                            captures += 1; -                        } -                        MoveKind::Castle => { -                            castles += 1; -                        } -                        _ => {} -                    } -                    if self.is_king_in_check(color.flip()) { -                        checks += 1; -                    } -                } - -                if print { -                    println!("{:?}", mov); -                    self.print(); -                } -                let (children_total, children_tactical, children_checks, children_castles, children_ep) = self.perft(depth - 1, print); -                total += children_total; -                captures += children_tactical; -                checks += children_checks; -                castles += children_castles; -                en_passants += children_ep; - -            } -            self.unmake_move(mov, captured_piece, ep_target_before, castling_rights_before); -        } - -        if print { -            println!("Found {} nodes in this subtree (depth {})", total, depth); -        } - -        (total, captures, checks, castles, en_passants) -    } -      fn is_square_attacked(&self, square: Square, attacker_color: Color) -> bool {          let square_bb = square.to_bitboard();          for (piece_type, piece) in self.pieces_by_color(attacker_color).iter().enumerate() { @@ -611,49 +546,6 @@ 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 -    }  } @@ -796,29 +688,6 @@ mod tests {      }      #[test] -    fn perft() { -        let mut board = Board::new(); - -        assert_eq!(board.perft(0, false), (1, 0, 0, 0, 0)); -        assert_eq!(board.perft(1, false), (20, 0, 0, 0, 0)); -        assert_eq!(board.perft(2, false), (400, 0, 0, 0, 0)); -        assert_eq!(board.perft(3, false), (8902, 34, 12, 0, 0)); -        assert_eq!(board.perft(4, false), (197281, 1576, 469, 0, 0)); -        // assert_eq!(board.perft(5, false), (4865609, 82719, 27351, 0, 258)); -        // assert_eq!(board.perft(6, false), (119060324, 2812008, 809099, 0, 5248)); -    } - -    #[test] -    fn position_perft() { -        let fen = String::from("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - "); -        let mut board = Board::from_FEN(fen); -        assert_eq!(board.perft(0, false), (1, 0, 0, 0, 0)); -        assert_eq!(board.perft(1, false), (48, 8, 0, 2, 0)); -        assert_eq!(board.perft(2, false), (2039, 351, 3, 91, 1)); -        assert_eq!(board.perft(3, false), (97862, 17102, 993, 3162, 45)); -    } - -    #[test]      fn is_square_attacked() {          let board = Board::new(); @@ -828,12 +697,4 @@ mod tests {          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); -    }  } | 
