[board] Implement PawnMoveGenerator
It generates pawn moves with bitboard bit operations!
This commit is contained in:
parent
65a7bec5f9
commit
852b7a848f
4 changed files with 183 additions and 1 deletions
|
@ -1,5 +1,6 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
mod move_generator;
|
||||
mod pawn;
|
||||
|
||||
pub use move_generator::MoveGenerator;
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
172
board/src/moves/pawn.rs
Normal file
172
board/src/moves/pawn.rs
Normal file
|
@ -0,0 +1,172 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue