[bitboard, core, position] Implement proper castle move generation

Add a field to MoveSet called special that flags special moves that should be
generated in the iter() method. This field is a u8. It only tracks castles in
the first and second bits (kingside and queenside, respectively). The move iterator
chains two maps over Option<()> that produce the kingside and queenside castle
moves.

With that done, finish the implementation of Position::player_can_castle by
adding checks for whether the squares between the rook and king are clear, and
that the king would not pass through a check. This is done with BitBoards!

Finally, implement some logic in PositionBuilder that updates the position's
castling flags based on the positions of king and rooks.

Supporting changes:
- Add Color:ALL and iterate on that slice
- Add Castle::ALL and iterator on that slice
- Add a CastlingParameters struct that contains BitBoard properties that describe
  squares that should be clear of pieces and squares that should not be attacked.
This commit is contained in:
Eryn Wells 2024-01-29 14:44:48 -08:00
parent 83a4e47e56
commit 1d7dada987
6 changed files with 234 additions and 60 deletions

View file

@ -1,6 +1,6 @@
// Eryn Wells <eryn@erynwells.me>
use crate::{Move, MoveBuilder};
use crate::{r#move::Castle, Move, MoveBuilder};
use chessfriend_bitboard::BitBoard;
use chessfriend_core::{Color, Piece, PlacedPiece, Shape};
@ -27,7 +27,7 @@ impl MoveListSet {
pub(crate) struct MoveSet {
piece: PlacedPiece,
bitboards: BitBoardSet,
move_lists: MoveListSet,
special: u8,
}
impl MoveSet {
@ -35,10 +35,7 @@ impl MoveSet {
MoveSet {
piece,
bitboards: BitBoardSet::default(),
move_lists: MoveListSet {
quiet: Vec::new(),
captures: Vec::new(),
},
special: 0,
}
}
@ -52,6 +49,16 @@ impl MoveSet {
self
}
pub(super) fn kingside_castle(&mut self) -> &mut MoveSet {
self.special |= 0b1;
self
}
pub(super) fn queenside_castle(&mut self) -> &mut MoveSet {
self.special |= 0b10;
self
}
/// Return a BitBoard representing all possible moves.
pub(super) fn bitboard(&self) -> BitBoard {
self.bitboards.captures | self.bitboards.quiet
@ -78,5 +85,37 @@ impl MoveSet {
.build()
}),
)
.chain(
if (self.special & 0b1) != 0 {
Some(())
} else {
None
}
.map(|()| {
MoveBuilder::new(
*piece,
from_square,
Castle::KingSide.target_squares(piece.color()).king,
)
.castle(Castle::KingSide)
.build()
}),
)
.chain(
if (self.special & 0b10) != 0 {
Some(())
} else {
None
}
.map(|()| {
MoveBuilder::new(
*piece,
from_square,
Castle::QueenSide.target_squares(piece.color()).king,
)
.castle(Castle::QueenSide)
.build()
}),
)
}
}