[explorer, moves, position] Implement bespoke make_move and unmake_move methods on Position

Instead of inheriting the MakeMove and UnmakeMove traits by being a BoardProvider,
implement bespoke versions of these two methods. This gives Position a chance to
do some of its own work (tracking captures, move records, etc) when making a move.

Pass the move record by reference to the unmake_move() method. Saves a copy.

Export the Result types for MakeMove and UnmakeMove.
This commit is contained in:
Eryn Wells 2025-06-01 19:02:53 -07:00
parent 724a98c2e2
commit 8f42a4c94e
5 changed files with 66 additions and 45 deletions

View file

@ -1,21 +1,20 @@
// Eryn Wells <eryn@erynwells.me>
mod captures;
mod unmake_move;
use chessfriend_moves::{
generators::{
AllPiecesMoveGenerator, BishopMoveGenerator, KingMoveGenerator, KnightMoveGenerator,
PawnMoveGenerator, QueenMoveGenerator, RookMoveGenerator,
},
GeneratedMove, MakeMove, Move, MoveRecord, ValidateMove,
GeneratedMove, MakeMove, MakeMoveError, Move, MoveRecord, UnmakeMove, UnmakeMoveError,
UnmakeMoveResult, ValidateMove,
};
use captures::CapturesList;
use chessfriend_bitboard::BitBoard;
use chessfriend_board::{
display::DiagramFormatter, fen::ToFenStr, Board, BoardProvider, PlacePieceError,
PlacePieceStrategy,
display::DiagramFormatter, fen::ToFenStr, Board, PlacePieceError, PlacePieceStrategy,
};
use chessfriend_core::{Color, Piece, Shape, Square};
use std::fmt;
@ -127,6 +126,45 @@ impl Position {
}
}
impl Position {
/// Make a move on the board and record it in the move list.
///
/// ## Errors
///
/// Returns one of [`MakeMoveError`] if the move cannot be made.
///
pub fn make_move(&mut self, ply: Move, validate: ValidateMove) -> Result<(), MakeMoveError> {
let record = self.board.make_move(ply, validate)?;
if let Some(captured_piece) = record.captured_piece {
self.captures.push(record.color, captured_piece);
}
self.moves.push(record.clone());
Ok(())
}
/// Unmake the last move made on the board and remove its record from the
/// move list.
///
/// ## Errors
///
/// Returns one of [`UnmakeMoveError`] if the move cannot be made.
///
pub fn unmake_last_move(&mut self) -> UnmakeMoveResult {
let last_move_record = self.moves.pop().ok_or(UnmakeMoveError::NoMove)?;
let unmake_result = self.board.unmake_move(&last_move_record);
if unmake_result.is_err() {
self.moves.push(last_move_record);
}
unmake_result
}
}
impl Position {
pub fn display(&self) -> DiagramFormatter {
self.board.display()
@ -141,16 +179,6 @@ impl ToFenStr for Position {
}
}
impl BoardProvider for Position {
fn board(&self) -> &Board {
&self.board
}
fn board_mut(&mut self) -> &mut Board {
&mut self.board
}
}
impl PartialEq for Position {
fn eq(&self, other: &Self) -> bool {
self.board == other.board