[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>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
mod move_generator;
|
mod move_generator;
|
||||||
|
mod pawn;
|
||||||
|
|
||||||
pub use move_generator::MoveGenerator;
|
pub use move_generator::MoveGenerator;
|
||||||
|
|
|
@ -2,12 +2,19 @@
|
||||||
|
|
||||||
use crate::Position;
|
use crate::Position;
|
||||||
|
|
||||||
|
use super::pawn::PawnMoveGenerator;
|
||||||
|
|
||||||
pub struct MoveGenerator<'a> {
|
pub struct MoveGenerator<'a> {
|
||||||
pub(super) position: &'a Position,
|
pub(super) position: &'a Position,
|
||||||
|
|
||||||
|
pawn_move_generator: PawnMoveGenerator<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MoveGenerator<'a> {
|
impl<'a> MoveGenerator<'a> {
|
||||||
pub fn new(position: &Position) -> MoveGenerator {
|
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 {
|
impl Square {
|
||||||
|
sq_constructor!(d5);
|
||||||
sq_constructor!(e2);
|
sq_constructor!(e2);
|
||||||
sq_constructor!(e3);
|
sq_constructor!(e3);
|
||||||
sq_constructor!(e4);
|
sq_constructor!(e4);
|
||||||
|
sq_constructor!(f5);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue