aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreug-vs <eugene@eug-vs.xyz>2023-01-23 07:37:49 +0300
committereug-vs <eugene@eug-vs.xyz>2023-01-23 07:37:49 +0300
commita54e9b4fbb44f0396a4e79d60b88043005012295 (patch)
tree3bbfecfc1add90cb098e9bc1a42f4f2e885bd721
parentbf224cd6b8514b1dcf135b4d3a1744c39500726f (diff)
downloadchessnost-a54e9b4fbb44f0396a4e79d60b88043005012295.tar.gz
feat: implement unmake_move
-rw-r--r--src/attacks.rs2
-rw-r--r--src/board.rs63
2 files changed, 55 insertions, 10 deletions
diff --git a/src/attacks.rs b/src/attacks.rs
index 1ccd0cf..5399c96 100644
--- a/src/attacks.rs
+++ b/src/attacks.rs
@@ -38,7 +38,7 @@ enum Direction {
NoWe,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Attacks {
pub knight: AttackTable,
pub king: AttackTable,
diff --git a/src/board.rs b/src/board.rs
index 2afbe90..ef8dde7 100644
--- a/src/board.rs
+++ b/src/board.rs
@@ -2,7 +2,7 @@ use crate::{bitboard::{Bitboard, serialize_bitboard}, moves::Move, attacks::Atta
pub static DEFAULT_FEN: &str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Board {
pub pieces: [Bitboard; 12],
@@ -201,28 +201,28 @@ impl Board {
/// *Blindlessly* apply a move without any validation
/// Move should be validated beforehand
pub fn make_move(&mut self, mov: Move) -> Option<PieceType> {
- // Target
+ // Remove existing piece (if any) from target square
let captured_piece = match self.pieces
.iter()
.enumerate()
.find(|(piece_type, bitboard)| *bitboard & mov.target.to_bitboard() > 0)
{
- Some((piece_type, _)) => {
- self.pieces[piece_type] ^= mov.target.to_bitboard();
- Some(PieceType::from(piece_type))
+ Some((target_piece, _)) => {
+ self.pieces[target_piece] ^= mov.target.to_bitboard();
+ Some(PieceType::from(target_piece))
},
None => None,
};
- // Source
+ // Move a piece from source square to target
match self.pieces
.iter()
.enumerate()
.find(|(piece_type, bitboard)| *bitboard & mov.source.to_bitboard() > 0)
{
- Some((piece_type, _)) => {
- self.pieces[piece_type] ^= mov.source.to_bitboard();
- self.pieces[piece_type] |= mov.target.to_bitboard();
+ Some((source_piece, _)) => {
+ self.pieces[source_piece] ^= mov.source.to_bitboard();
+ self.pieces[source_piece] |= mov.target.to_bitboard();
},
None => panic!("Move is malformed: source piece not found"),
};
@@ -232,6 +232,33 @@ impl Board {
captured_piece
}
+
+ /// Completely reverse make_move as if it never happened
+ pub fn unmake_move(&mut self, mov: Move, captured_piece: Option<PieceType>) {
+ // Remove source piece from target square
+ match self.pieces
+ .iter()
+ .enumerate()
+ .find(|(piece_type, bitboard)| *bitboard & mov.target.to_bitboard() > 0)
+ {
+ Some((source_piece, _)) => {
+ self.pieces[source_piece] ^= mov.target.to_bitboard();
+ self.pieces[source_piece] |= mov.source.to_bitboard();
+ },
+ None => panic!("Trying to unmake move which was not made: no piece was found on target square"),
+ };
+
+ // Return captured piece to target square
+ match captured_piece {
+ Some(target_piece) => {
+ self.pieces[target_piece as usize] |= mov.target.to_bitboard();
+ },
+ None => {}
+ }
+
+ self.update_occupancy();
+ self.ply -= 1;
+ }
}
@@ -335,6 +362,24 @@ mod tests {
assert!(board.pieces[PieceType::Queen as usize] & Square::D2.to_bitboard() == 0);
assert!(board.pieces[PieceType::Queen as usize] & Square::A5.to_bitboard() > 0);
assert!(board.ply == 2);
+ }
+
+ #[test]
+ fn test_unmake_move() {
+ let fen = String::from("q1b2k2/5p1p/4p1pb/pPPp4/3N4/3nPB2/P2QKnR1/1R6 w - - 0 25");
+ let mut board = Board::from_FEN(fen);
+ let initial_board = board.clone();
+
+ let mov = Move { source: Square::D2, target: Square::A5 };
+
+ board.print();
+
+ let captured_piece = board.make_move(mov);
+ board.print();
+
+ board.unmake_move(mov, captured_piece);
+ board.print();
+ assert_eq!(board, initial_board, "Board state after unmake_move should be the same as before make_move");
}
}