[position, moves] Implement some castling tests
Add white castling for both wings. Found some bugs in how king sight is computed while writing these. In order for the king to perform the castle, the Movement bitboard needs to return the two squares the king can castle to. That means anytime movement is calculated for the king, the (relatively expensive) castling evaluation needs to happen. Write two new helper static functions to create a Move for castling and promotion moves. Since structs cannot have any functions with the same name, the two methods that return properties related to those moves (Move::castle and Move::promotion) need to be renamed. They're now called Move::castle_wing and Move::promotion_shape.
This commit is contained in:
parent
7c9c5484ba
commit
feaa81bbd8
5 changed files with 99 additions and 27 deletions
|
@ -4,17 +4,17 @@
|
|||
//! of squares a piece can move to. For all pieces except pawns, the Movement
|
||||
//! set is equal to the Sight set.
|
||||
|
||||
use crate::sight::Sight;
|
||||
use crate::{sight::Sight, Position};
|
||||
use chessfriend_bitboard::BitBoard;
|
||||
use chessfriend_board::Board;
|
||||
use chessfriend_core::{Color, Piece, Rank, Shape, Square};
|
||||
use chessfriend_core::{Color, Piece, Rank, Shape, Square, Wing};
|
||||
|
||||
pub trait Movement {
|
||||
fn movement(&self, square: Square, board: &Board) -> BitBoard;
|
||||
fn movement(&self, square: Square, position: &Position) -> BitBoard;
|
||||
}
|
||||
|
||||
impl Movement for Piece {
|
||||
fn movement(&self, square: Square, board: &Board) -> BitBoard {
|
||||
fn movement(&self, square: Square, position: &Position) -> BitBoard {
|
||||
let board = &position.board;
|
||||
let opposing_occupancy = board.opposing_occupancy(self.color);
|
||||
|
||||
match self.shape {
|
||||
|
@ -25,6 +25,25 @@ impl Movement for Piece {
|
|||
let pushes = pawn_pushes(square.into(), self.color, board.occupancy());
|
||||
sight | pushes
|
||||
}
|
||||
Shape::King => {
|
||||
let kingside_target_square =
|
||||
if position.active_color_can_castle(Wing::KingSide).is_ok() {
|
||||
let parameters = board.castling_parameters(Wing::KingSide);
|
||||
parameters.target.king.into()
|
||||
} else {
|
||||
BitBoard::empty()
|
||||
};
|
||||
|
||||
let queenside_target_square =
|
||||
if position.active_color_can_castle(Wing::QueenSide).is_ok() {
|
||||
let parameters = board.castling_parameters(Wing::QueenSide);
|
||||
parameters.target.king.into()
|
||||
} else {
|
||||
BitBoard::empty()
|
||||
};
|
||||
|
||||
self.sight(square, board) | kingside_target_square | queenside_target_square
|
||||
}
|
||||
_ => self.sight(square, board),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ impl Position {
|
|||
return self.make_capture_move(ply);
|
||||
}
|
||||
|
||||
if let Some(wing) = ply.castle() {
|
||||
if let Some(wing) = ply.castle_wing() {
|
||||
return self.make_castle_move(wing);
|
||||
}
|
||||
|
||||
|
@ -265,7 +265,7 @@ impl Position {
|
|||
// Pawns can see squares they can't move to. So, calculating valid
|
||||
// squares requires a concept that includes Sight, but adds pawn pushes.
|
||||
// In ChessFriend, that concept is Movement.
|
||||
let movement = active_piece.movement(origin_square, &self.board);
|
||||
let movement = active_piece.movement(origin_square, self);
|
||||
if !movement.contains(target_square) {
|
||||
return Err(MakeMoveError::NoMove {
|
||||
piece: active_piece,
|
||||
|
@ -408,4 +408,50 @@ mod tests {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn make_white_kingside_castle() -> MakeMoveResult {
|
||||
let mut pos = test_position![
|
||||
White Rook on H1,
|
||||
White King on E1,
|
||||
];
|
||||
|
||||
let ply = Move::castle(Square::E1, Square::G1, Wing::KingSide);
|
||||
pos.make_move(ply, ValidateMove::Yes)?;
|
||||
|
||||
assert_eq!(pos.board.active_color, Color::Black);
|
||||
assert_eq!(pos.get_piece(Square::E1), None);
|
||||
assert_eq!(pos.get_piece(Square::H1), None);
|
||||
assert_eq!(pos.get_piece(Square::G1), Some(piece!(White King)));
|
||||
assert_eq!(pos.get_piece(Square::F1), Some(piece!(White Rook)));
|
||||
assert!(!pos
|
||||
.board
|
||||
.castling_rights
|
||||
.color_has_right(Color::White, Wing::KingSide));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn make_white_queenside_castle() -> MakeMoveResult {
|
||||
let mut pos = test_position![
|
||||
White King on E1,
|
||||
White Rook on A1,
|
||||
];
|
||||
|
||||
let ply = Move::castle(Square::E1, Square::C1, Wing::QueenSide);
|
||||
pos.make_move(ply, ValidateMove::Yes)?;
|
||||
|
||||
assert_eq!(pos.board.active_color, Color::Black);
|
||||
assert_eq!(pos.get_piece(Square::E1), None);
|
||||
assert_eq!(pos.get_piece(Square::A1), None);
|
||||
assert_eq!(pos.get_piece(Square::C1), Some(piece!(White King)));
|
||||
assert_eq!(pos.get_piece(Square::D1), Some(piece!(White Rook)));
|
||||
assert!(!pos
|
||||
.board
|
||||
.castling_rights
|
||||
.color_has_right(Color::White, Wing::QueenSide));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ impl Position {
|
|||
|
||||
pub fn movement(&self, square: Square) -> BitBoard {
|
||||
if let Some(piece) = self.get_piece(square) {
|
||||
piece.movement(square, &self.board)
|
||||
piece.movement(square, self)
|
||||
} else {
|
||||
BitBoard::empty()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue