Skip to content

Commit 2445ff7

Browse files
committed
feat: undo move
1 parent d8f5a67 commit 2445ff7

File tree

2 files changed

+102
-2
lines changed

2 files changed

+102
-2
lines changed

src/board/mod.rs

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,13 @@ impl Board {
110110
moves: Vec::new(),
111111
zobrist_history: Vec::new(),
112112
fen_history: Vec::new(),
113-
game_state_history: Vec::new(),
113+
game_state_history: vec![GameState {
114+
captured_piece: None,
115+
en_passant_square: None,
116+
castling_rights: CASTLING_RIGHTS[0] | CASTLING_RIGHTS[1],
117+
fifty_move_ply_count: 0,
118+
current_zobrist: 0,
119+
}],
114120
}
115121
}
116122

@@ -136,7 +142,7 @@ impl Board {
136142
self.moves = Vec::new();
137143
self.zobrist_history = Vec::new();
138144
self.fen_history = Vec::new();
139-
self.game_state_history = Vec::new();
145+
self.game_state_history = vec![self.game_state];
140146
}
141147

142148
pub fn set_fen(&mut self, fen: &str) {
@@ -482,4 +488,55 @@ impl Board {
482488
self.fen_history.push(self.to_fen());
483489
self.moves.push(*mv);
484490
}
491+
492+
pub fn undo_move(&mut self, mv: &Move) {
493+
self.turn = self.turn.opposite();
494+
let last_move = self.moves.pop().unwrap();
495+
496+
if last_move != *mv {
497+
panic!("Invalid move");
498+
}
499+
500+
if mv.promotion == Some(Piece::Pawn) {
501+
self.remove_piece(mv.color, mv.promotion.unwrap(), mv.to);
502+
self.add_piece(mv.color, Piece::Pawn, mv.to);
503+
}
504+
505+
self.move_piece(mv.color, mv.piece, mv.to, mv.from);
506+
507+
if mv.capture.is_some() {
508+
let mut capture_square = mv.to as i32;
509+
510+
if mv.en_passant {
511+
capture_square -= match mv.color {
512+
Color::White => MOVE_DOWN,
513+
Color::Black => MOVE_UP,
514+
};
515+
}
516+
517+
self.add_piece(
518+
mv.color.opposite(),
519+
mv.capture.unwrap(),
520+
capture_square as usize,
521+
);
522+
}
523+
524+
if mv.piece == Piece::King {
525+
if mv.castling {
526+
let (rook_from, rook_to) = match mv.to {
527+
2 => (0, 3),
528+
6 => (7, 5),
529+
_ => panic!("Invalid castling move"),
530+
};
531+
532+
self.move_piece(mv.color, Piece::Rook, rook_to, rook_from);
533+
}
534+
}
535+
536+
self.game_state_history.pop();
537+
self.game_state = self.game_state_history.last().unwrap().clone();
538+
self.zobrist_history.pop();
539+
self.fen_history.pop();
540+
self.ply -= 1;
541+
}
485542
}

tests/board_tests.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,4 +755,47 @@ mod tests {
755755

756756
assert_eq!(castling, castling_assert);
757757
}
758+
759+
#[test]
760+
fn test_make_move() {
761+
let mut board = Board::init();
762+
let mv = Move {
763+
from: 12,
764+
to: 28,
765+
piece: Piece::Pawn,
766+
color: Color::White,
767+
en_passant: false,
768+
castling: false,
769+
promotion: None,
770+
capture: None,
771+
};
772+
773+
board.make_move(&mv);
774+
775+
assert!(board.pieces[Color::White as usize][Piece::Pawn as usize].is_set(28));
776+
assert!(!board.pieces[Color::White as usize][Piece::Pawn as usize].is_set(12));
777+
}
778+
779+
#[test]
780+
fn test_undo_move() {
781+
let mut board = Board::init();
782+
let fen_before = board.to_fen();
783+
let mv = Move {
784+
from: 12,
785+
to: 28,
786+
piece: Piece::Pawn,
787+
color: Color::White,
788+
en_passant: false,
789+
castling: false,
790+
promotion: None,
791+
capture: None,
792+
};
793+
794+
board.make_move(&mv);
795+
board.undo_move(&mv);
796+
797+
assert!(board.pieces[Color::White as usize][Piece::Pawn as usize].is_set(12));
798+
assert!(!board.pieces[Color::White as usize][Piece::Pawn as usize].is_set(28));
799+
assert_eq!(fen_before, board.to_fen());
800+
}
758801
}

0 commit comments

Comments
 (0)