diff --git a/board/src/moves/mod.rs b/board/src/moves/mod.rs index a3fe9ae..d5cf0d6 100644 --- a/board/src/moves/mod.rs +++ b/board/src/moves/mod.rs @@ -1,5 +1,6 @@ // Eryn Wells mod move_generator; +mod pawn; pub use move_generator::MoveGenerator; diff --git a/board/src/moves/move_generator.rs b/board/src/moves/move_generator.rs index ebb6d1a..7a0d01f 100644 --- a/board/src/moves/move_generator.rs +++ b/board/src/moves/move_generator.rs @@ -2,12 +2,19 @@ use crate::Position; +use super::pawn::PawnMoveGenerator; + pub struct MoveGenerator<'a> { pub(super) position: &'a Position, + + pawn_move_generator: PawnMoveGenerator<'a>, } impl<'a> MoveGenerator<'a> { pub fn new(position: &Position) -> MoveGenerator { - MoveGenerator { position } + MoveGenerator { + position, + pawn_move_generator: PawnMoveGenerator::new(position), + } } } diff --git a/board/src/moves/pawn.rs b/board/src/moves/pawn.rs new file mode 100644 index 0000000..c48d2a7 --- /dev/null +++ b/board/src/moves/pawn.rs @@ -0,0 +1,172 @@ +// Eryn Wells + +use crate::bitboard::BitBoard; +use crate::piece::{Color, Piece}; +use crate::Position; + +pub(super) struct PawnMoveGenerator<'a> { + position: &'a Position, +} + +impl<'a> PawnMoveGenerator<'a> { + pub(super) fn new(position: &Position) -> PawnMoveGenerator { + PawnMoveGenerator { position } + } + + pub(super) fn pawn_moves(&self, color: Color) -> BitBoard { + match color { + Color::White => self.white_pawn_pushes() & self.white_pawn_attacks(), + Color::Black => self.black_pawn_pushes() & self.black_pawn_attacks(), + } + } + + pub(super) fn pawn_attacks(&self, color: Color) -> BitBoard { + match color { + Color::White => self.white_pawn_attacks(), + Color::Black => self.black_pawn_attacks(), + } + } + + pub(super) fn pawn_pushes(&self, color: Color) -> BitBoard { + match color { + Color::White => self.white_pawn_pushes(), + Color::Black => self.black_pawn_pushes(), + } + } + + fn white_pawn_pushes(&self) -> BitBoard { + let empty_squares = self.position.empty_squares(); + let bb = self.position.bitboard_for_piece(Piece::pawn(Color::White)); + + let legal_1square_pushes = bb.shift_north_one() & empty_squares; + let legal_2square_pushes = + (legal_1square_pushes & BitBoard::rank(2)).shift_north_one() & empty_squares; + + legal_1square_pushes | legal_2square_pushes + } + + fn white_pawn_attacks(&self) -> BitBoard { + let black_pieces = self.position.bitboard_for_color(Color::Black); + let bb = self.position.bitboard_for_piece(Piece::pawn(Color::White)); + + (bb.shift_north_east_one() | bb.shift_north_west_one()) & black_pieces + } + + fn black_pawn_pushes(&self) -> BitBoard { + let empty_squares = self.position.empty_squares(); + let bb = self.position.bitboard_for_piece(Piece::pawn(Color::Black)); + + let legal_1square_pushes = bb.shift_south_one() & empty_squares; + let legal_2square_pushes = + (legal_1square_pushes & BitBoard::rank(5)).shift_south_one() & empty_squares; + + legal_1square_pushes | legal_2square_pushes + } + + fn black_pawn_attacks(&self) -> BitBoard { + let white_pieces = self.position.bitboard_for_color(Color::White); + let bb = self.position.bitboard_for_piece(Piece::pawn(Color::Black)); + + (bb.shift_south_east_one() | bb.shift_south_west_one()) & white_pieces + } + + // TODO: En passant +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::position::DiagramFormatter; + use crate::{Position, Square}; + + #[test] + fn one_2square_push() { + let mut pos = Position::empty(); + pos.place_piece(&Piece::pawn(Color::White), &Square::e2()) + .expect("Failed to place pawn on e2"); + + let generator = PawnMoveGenerator::new(&pos); + let pawn_pushes = generator.pawn_pushes(Color::White); + + let mut expected = BitBoard::empty(); + expected.place_piece_at(&Square::e3()); + expected.place_piece_at(&Square::e4()); + + assert_eq!(pawn_pushes, expected); + } + + #[test] + fn one_1square_push() { + let mut pos = Position::empty(); + pos.place_piece(&Piece::pawn(Color::White), &Square::e3()) + .expect("Failed to place pawn on e3"); + + let generator = PawnMoveGenerator::new(&pos); + let pawn_pushes = generator.pawn_pushes(Color::White); + + let mut expected = BitBoard::empty(); + expected.place_piece_at(&Square::e4()); + + assert_eq!(pawn_pushes, expected); + } + + #[test] + fn one_obstructed_2square_push() { + let mut pos = Position::empty(); + pos.place_piece(&Piece::pawn(Color::White), &Square::e2()) + .expect("Failed to place pawn on e2"); + pos.place_piece(&Piece::knight(Color::White), &Square::e4()) + .expect("Failed to place knight on e4"); + + println!("{}", DiagramFormatter::new(&pos)); + + let generator = PawnMoveGenerator::new(&pos); + let pawn_pushes = generator.white_pawn_pushes(); + + let mut expected = BitBoard::empty(); + expected.place_piece_at(&Square::e3()); + + assert_eq!(pawn_pushes, expected); + } + + #[test] + fn one_attack() { + let mut pos = Position::empty(); + pos.place_piece(&Piece::pawn(Color::White), &Square::e4()) + .expect("Failed to place pawn on e4"); + pos.place_piece(&Piece::knight(Color::Black), &Square::d5()) + .expect("Failed to place knight on d5"); + + println!("{}", DiagramFormatter::new(&pos)); + + let generator = PawnMoveGenerator::new(&pos); + let pawn_attacks = generator.white_pawn_attacks(); + + let mut expected = BitBoard::empty(); + expected.place_piece_at(&Square::d5()); + + assert_eq!(pawn_attacks, expected); + } + + #[test] + fn one_double_attack() { + let mut pos = Position::empty(); + pos.place_piece(&Piece::pawn(Color::White), &Square::e4()) + .expect("Failed to place pawn on e4"); + pos.place_piece(&Piece::knight(Color::Black), &Square::d5()) + .expect("Failed to place knight on d5"); + pos.place_piece(&Piece::queen(Color::Black), &Square::f5()) + .expect("Failed to place knight on f5"); + + println!("{}", DiagramFormatter::new(&pos)); + + let generator = PawnMoveGenerator::new(&pos); + let pawn_attacks = generator.white_pawn_attacks(); + + let mut expected = BitBoard::empty(); + expected.place_piece_at(&Square::d5()); + expected.place_piece_at(&Square::f5()); + + assert_eq!(pawn_attacks, expected); + } +} diff --git a/board/src/tests.rs b/board/src/tests.rs index 2a90a89..0dd5392 100644 --- a/board/src/tests.rs +++ b/board/src/tests.rs @@ -14,7 +14,9 @@ macro_rules! sq_constructor { } impl Square { + sq_constructor!(d5); sq_constructor!(e2); sq_constructor!(e3); sq_constructor!(e4); + sq_constructor!(f5); }