aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoreug-vs <eugene@eug-vs.xyz>2023-01-23 12:48:03 +0300
committereug-vs <eugene@eug-vs.xyz>2023-01-23 12:48:03 +0300
commite65b0854174c9c90d5eff850428fd07c6912960c (patch)
treed281c0da8368da6b922eac8f12f65f4f4ae4281b /src
parente6102cda73e854b3050cceb86b9f66bac0b81345 (diff)
downloadchessnost-e65b0854174c9c90d5eff850428fd07c6912960c.tar.gz
feat: basic En Passant implementation
Diffstat (limited to 'src')
-rw-r--r--src/board.rs61
-rw-r--r--src/moves.rs1
-rw-r--r--src/square.rs16
3 files changed, 71 insertions, 7 deletions
diff --git a/src/board.rs b/src/board.rs
index 186e569..58e4037 100644
--- a/src/board.rs
+++ b/src/board.rs
@@ -185,7 +185,7 @@ impl Board {
};
for source in serialize_bitboard(*piece & able_to_double_push_mask) {
for target in serialize_bitboard(self.attacks.pawn_double_pushes[color as usize][source as usize] & empty) {
- moves.push(Move { source, target, kind: MoveKind::Quiet });
+ moves.push(Move { source, target, kind: MoveKind::DoublePush });
};
}
}
@@ -254,7 +254,7 @@ impl Board {
let move_target_bb = mov.target.to_bitboard();
// Remove existing piece (if any) from target square
- let captured_piece = match self.pieces
+ let mut captured_piece = match self.pieces
.iter()
.enumerate()
.find(|(piece_type, bitboard)| *bitboard & mov.target.to_bitboard() > 0)
@@ -266,6 +266,26 @@ impl Board {
None => None,
};
+ // En Passant captures diffirently
+ captured_piece = match mov.kind {
+ MoveKind::EnPassant => {
+ debug_assert!(captured_piece.is_none(), "No capture should be found at this point");
+ let captured_bb = Square::from(mov.source.rank() * 8 + mov.target.file()).to_bitboard();
+ match self.pieces
+ .iter()
+ .enumerate()
+ .find(|(piece_type, bitboard)| *bitboard & captured_bb > 0)
+ {
+ Some((pawn_type, _)) => {
+ self.pieces[pawn_type] ^= captured_bb;
+ Some(PieceType::from(pawn_type))
+ }
+ None => panic!("Pawn captured by En Passant was not found"),
+ }
+ },
+ _ => captured_piece,
+ };
+
// Move a piece from source square to target
match self.pieces
.iter()
@@ -282,13 +302,27 @@ impl Board {
None => panic!("Move is malformed: source piece not found"),
};
+ // Double push should set En Passant target square
+ match mov.kind {
+ MoveKind::DoublePush => {
+ self.ep_target = match mov.source.rank() {
+ 1 => Some(mov.source.nort_one()),
+ 6 => Some(mov.source.sout_one()),
+ rank => panic!("Double-push was used from invalid rank({}) when trying to make {:?}", rank, mov),
+ };
+ },
+ _ => {
+ self.ep_target = None
+ },
+ }
+
self.ply += 1;
captured_piece
}
/// Completely reverse make_move as if it never happened
- pub fn unmake_move(&mut self, mov: Move, captured_piece: Option<PieceType>) {
+ pub fn unmake_move(&mut self, mov: Move, captured_piece: Option<PieceType>, previous_ep_target: Option<Square>) {
let move_source_bb = mov.source.to_bitboard();
let move_target_bb = mov.target.to_bitboard();
@@ -311,12 +345,24 @@ impl Board {
// Return captured piece to target square
match captured_piece {
Some(target_piece) => {
- self.pieces[target_piece as usize] |= move_target_bb;
- self.occupancy |= move_target_bb;
+ match mov.kind {
+ // Return pawn captured by En Passant pawn if needed
+ MoveKind::EnPassant => {
+ let original_dead_pawn_bb = Square::from(mov.source.rank() * 8 + mov.target.file()).to_bitboard();
+ self.pieces[target_piece as usize] |= original_dead_pawn_bb;
+ self.occupancy |= original_dead_pawn_bb;
+ },
+ _ => {
+ self.pieces[target_piece as usize] |= move_target_bb;
+ self.occupancy |= move_target_bb;
+ },
+ }
},
None => {}
}
+
+ self.ep_target = previous_ep_target;
self.ply -= 1;
}
@@ -338,6 +384,7 @@ impl Board {
let mut checks = 0;
for mov in moves {
+ let ep_target_before = self.ep_target.clone();
let captured_piece = self.make_move(mov);
// King can not be in check after our own move
if !self.is_king_in_check(color) {
@@ -357,7 +404,7 @@ impl Board {
checks += children_checks;
}
- self.unmake_move(mov, captured_piece);
+ self.unmake_move(mov, captured_piece, ep_target_before);
}
if print {
@@ -539,7 +586,7 @@ mod tests {
let captured_piece = board.make_move(mov);
board.print();
- board.unmake_move(mov, captured_piece);
+ board.unmake_move(mov, captured_piece, None);
board.print();
assert_eq!(board, initial_board, "Board state after unmake_move should be the same as before make_move");
diff --git a/src/moves.rs b/src/moves.rs
index d6695a1..d0e3eb6 100644
--- a/src/moves.rs
+++ b/src/moves.rs
@@ -6,6 +6,7 @@ pub enum MoveKind {
Capture,
Castle,
EnPassant,
+ DoublePush,
}
#[derive(Debug, Clone, Copy)]
diff --git a/src/square.rs b/src/square.rs
index ed2877c..1adca83 100644
--- a/src/square.rs
+++ b/src/square.rs
@@ -19,6 +19,22 @@ impl Square {
pub fn to_bitboard(&self) -> Bitboard {
1u64 << *self as u8
}
+ /// 0-based rank
+ pub fn rank(&self) -> u8 {
+ *self as u8 / 8
+ }
+ /// 0-based file
+ pub fn file(&self) -> u8 {
+ *self as u8 % 8
+ }
+
+ pub fn nort_one(&self) -> Self {
+ Self::from(*self as u8 + 8)
+ }
+
+ pub fn sout_one(&self) -> Self {
+ Self::from(*self as u8 - 8)
+ }
}