Return a chessfriend_moves::EnPassant from a new Position::en_passant()

Replace Position's en_passant_target_square() and en_passant_capture_square()
with a single en_passant() method that returns a new EnPassant struct that has
the target and capture squares for the en passant move.
This commit is contained in:
Eryn Wells 2024-02-10 18:30:11 -07:00
parent cc23ee2d90
commit e6a9b7f8c4
8 changed files with 66 additions and 27 deletions

1
Cargo.lock generated
View file

@ -87,6 +87,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"chessfriend_bitboard", "chessfriend_bitboard",
"chessfriend_core", "chessfriend_core",
"chessfriend_moves",
] ]
[[package]] [[package]]

49
moves/src/en_passant.rs Normal file
View file

@ -0,0 +1,49 @@
// Eryn Wells <eryn@erynwells.me>
use chessfriend_core::{Rank, Square};
/// En passant information.
#[derive(Clone, Copy, Debug)]
pub struct EnPassant {
target: Square,
capture: Square,
}
impl EnPassant {
fn _capture_square(target: Square) -> Option<Square> {
let (file, rank) = target.file_rank();
match rank {
Rank::THREE => Some(Square::from_file_rank(file, Rank::FOUR)),
Rank::SIX => Some(Square::from_file_rank(file, Rank::FIVE)),
_ => None,
}
}
/// Return en passant information for a particular target square. The target
/// square is the square a pawn capturing en passant will move to.
///
/// Return `None` if the square is not eligible for en passant.
///
/// ## Examples
///
/// ```
/// use chessfriend_core::Square;
/// use chessfriend_moves::EnPassant;
/// assert!(EnPassant::from_target_square(Square::E3).is_some());
/// assert!(EnPassant::from_target_square(Square::B4).is_none());
/// ```
pub fn from_target_square(target: Square) -> Option<Self> {
match Self::_capture_square(target) {
Some(capture) => Some(Self { target, capture }),
None => None,
}
}
pub fn target_square(&self) -> Square {
self.target
}
pub fn capture_square(&self) -> Square {
self.capture
}
}

View file

@ -3,9 +3,11 @@
mod builder; mod builder;
mod castle; mod castle;
mod defs; mod defs;
mod en_passant;
mod moves; mod moves;
pub use builder::{Builder, Error as BuilderError}; pub use builder::{Builder, Error as BuilderError};
pub use castle::Castle; pub use castle::Castle;
pub use defs::PromotionShape; pub use defs::PromotionShape;
pub use en_passant::EnPassant;
pub use moves::Move; pub use moves::Move;

View file

@ -8,3 +8,4 @@ edition = "2021"
[dependencies] [dependencies]
chessfriend_core = { path = "../core" } chessfriend_core = { path = "../core" }
chessfriend_bitboard = { path = "../bitboard" } chessfriend_bitboard = { path = "../bitboard" }
chessfriend_moves = { path = "../moves" }

View file

@ -95,11 +95,8 @@ impl ToFen for Position {
write!( write!(
fen_string, fen_string,
" {}", " {}",
if let Some(en_passant_square) = self.en_passant_target_square() { self.en_passant()
en_passant_square.to_string() .map_or("-".to_string(), |ep| ep.target_square().to_string())
} else {
"-".to_string()
}
) )
.map_err(|err| ToFenError::FmtError(err))?; .map_err(|err| ToFenError::FmtError(err))?;

View file

@ -1,10 +1,6 @@
// Eryn Wells <eryn@erynwells.me> // Eryn Wells <eryn@erynwells.me>
use crate::{ use crate::{position::flags::Flags, r#move::Castle, MakeMoveError, Move, Position};
position::flags::Flags,
r#move::{AlgebraicMoveFormatter, Castle},
MakeMoveError, Move, Position,
};
use chessfriend_bitboard::BitBoard; use chessfriend_bitboard::BitBoard;
use chessfriend_core::{Color, Direction, Piece, PlacedPiece, Shape, Square}; use chessfriend_core::{Color, Direction, Piece, PlacedPiece, Shape, Square};
@ -292,7 +288,10 @@ mod tests {
new_position.piece_on_square(Square::E4), new_position.piece_on_square(Square::E4),
Some(piece!(White Pawn on E4)) Some(piece!(White Pawn on E4))
); );
assert_eq!(new_position.en_passant_target_square(), Some(Square::E3)); assert_eq!(
new_position.en_passant().map(|ep| ep.target_square()),
Some(Square::E3)
);
Ok(()) Ok(())
} }

View file

@ -52,7 +52,7 @@ impl Builder {
flags: position.flags(), flags: position.flags(),
pieces, pieces,
kings: [Some(white_king), Some(black_king)], kings: [Some(white_king), Some(black_king)],
en_passant_square: position.en_passant_target_square(), en_passant_square: position.en_passant().map(|ep| ep.target_square()),
ply_counter: position.ply_counter(), ply_counter: position.ply_counter(),
move_number: position.move_number(), move_number: position.move_number(),
} }

View file

@ -10,6 +10,7 @@ use crate::{
}; };
use chessfriend_bitboard::BitBoard; use chessfriend_bitboard::BitBoard;
use chessfriend_core::{Color, Piece, PlacedPiece, Rank, Shape, Square}; use chessfriend_core::{Color, Piece, PlacedPiece, Rank, Shape, Square};
use chessfriend_moves::EnPassant;
use std::{cell::OnceCell, fmt}; use std::{cell::OnceCell, fmt};
#[derive(Clone, Debug, Eq)] #[derive(Clone, Debug, Eq)]
@ -182,23 +183,12 @@ impl Position {
Pieces::new(&self, color) Pieces::new(&self, color)
} }
/// If en passant is available in this position, the square a pawn will move pub fn has_en_passant_square(&self) -> bool {
/// to if it captures en passant. self.en_passant_square.is_some()
pub fn en_passant_target_square(&self) -> Option<Square> {
self.en_passant_square
} }
/// If en passant is available in this position, the square on which the pub fn en_passant(&self) -> Option<EnPassant> {
/// captured pawn is sitting. EnPassant::from_target_square(self.en_passant_square?)
pub fn en_passant_capture_square(&self) -> Option<Square> {
let target_square = self.en_passant_square?;
let file = target_square.file();
Some(match target_square.rank() {
Rank::THREE => Square::from_file_rank(file, Rank::FOUR),
Rank::SIX => Square::from_file_rank(file, Rank::SEVEN),
_ => unreachable!(),
})
} }
fn _sight_of_player(&self, player: Color, pieces: &PieceBitBoards) -> BitBoard { fn _sight_of_player(&self, player: Color, pieces: &PieceBitBoards) -> BitBoard {