From 65aa6014833eda1d43e9881d6b1d6bd66f9634ac Mon Sep 17 00:00:00 2001 From: Tolly Date: Thu, 2 Mar 2023 13:52:11 +0000 Subject: [PATCH] Implement move undo --- ChessGame.cs | 13 ++++++++----- CustomGame.xaml.cs | 2 +- MainWindow.xaml | 2 ++ MainWindow.xaml.cs | 16 ++++++++++++++++ 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/ChessGame.cs b/ChessGame.cs index 9d61562..205f558 100644 --- a/ChessGame.cs +++ b/ChessGame.cs @@ -51,6 +51,7 @@ public class ChessGame /// public List<(Point, Point)> Moves { get; } public List MoveText { get; } + public ChessGame? PreviousGameState { get; private set; } public List CapturedPieces { get; } public Point? EnPassantSquare { get; private set; } @@ -110,7 +111,7 @@ public ChessGame() public ChessGame(Pieces.Piece?[,] board, bool currentTurnWhite, bool gameOver, List<(Point, Point)> moves, List moveText, List capturedPieces, Point? enPassantSquare, bool whiteMayCastleKingside, bool whiteMayCastleQueenside, bool blackMayCastleKingside, bool blackMayCastleQueenside, int staleMoveCounter, Dictionary boardCounts, - string? initialState) + string? initialState, ChessGame? previousGameState) { if (board.GetLength(0) != 8 || board.GetLength(1) != 8) { @@ -148,6 +149,7 @@ public ChessGame(Pieces.Piece?[,] board, bool currentTurnWhite, bool gameOver, L BoardCounts = boardCounts; InitialState = initialState ?? ToString(); + PreviousGameState = previousGameState; } /// @@ -167,7 +169,7 @@ public ChessGame Clone() return new ChessGame(boardClone, CurrentTurnWhite, GameOver, new(Moves), new(MoveText), CapturedPieces.Select(c => c.Clone()).ToList(), EnPassantSquare, WhiteMayCastleKingside, WhiteMayCastleQueenside, BlackMayCastleKingside, BlackMayCastleQueenside, StaleMoveCounter, - new(BoardCounts), InitialState); + new(BoardCounts), InitialState, PreviousGameState?.Clone()); } /// @@ -245,7 +247,7 @@ public bool IsCastlePossible(bool kingside) /// If a pawn is promoted, what should it be promoted to. means the user should be prompted for the type. /// /// - /// Whether the move should update the game move text. This should usually be , + /// Whether the move should update the game move text and update . This should usually be , /// but may be set to for performance optimisations in clone games for analysis. /// /// if the move was valid and executed, otherwise @@ -267,11 +269,12 @@ public bool MovePiece(Point source, Point destination, bool forceMove = false, T return false; } - // Used for generating new move text + // Used for generating new move text and move undoing ChessGame? oldGame = null; if (updateMoveText) { oldGame = Clone(); + PreviousGameState = oldGame; } bool pieceMoved; @@ -750,7 +753,7 @@ public static ChessGame FromForsythEdwards(string forsythEdwards) // For the PGN standard, if black moves first then a single move "..." is added to the start of the move text list return new ChessGame(board, currentTurnWhite, EndingStates.Contains(BoardAnalysis.DetermineGameState(board, currentTurnWhite)), new(), currentTurnWhite ? new() : new() { "..." }, new(), enPassant, whiteKingside, whiteQueenside, blackKingside, blackQueenside, - staleMoves, new(), null); + staleMoves, new(), null, null); } } } diff --git a/CustomGame.xaml.cs b/CustomGame.xaml.cs index 1905f55..24a7793 100644 --- a/CustomGame.xaml.cs +++ b/CustomGame.xaml.cs @@ -145,7 +145,7 @@ private void startButton_Click(object sender, RoutedEventArgs e) ChessGame.EndingStates.Contains(BoardAnalysis.DetermineGameState(Board, currentTurnWhite)), new(), currentTurnWhite ? new() : new() { "..." }, new(), EnPassantSquare, castleWhiteKingside.IsChecked ?? false, castleWhiteQueenside.IsChecked ?? false, castleBlackKingside.IsChecked ?? false, - castleBlackQueenside.IsChecked ?? false, 0, new(), null); + castleBlackQueenside.IsChecked ?? false, 0, new(), null, null); Close(); } diff --git a/MainWindow.xaml b/MainWindow.xaml index 8e963c5..b5ee4f1 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -23,6 +23,8 @@ + + diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index dd0564d..8dad05b 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -899,6 +899,22 @@ private void CustomiseItem_Click(object sender, RoutedEventArgs e) UpdateGameDisplay(); } + private async void UndoMove_Click(object sender, RoutedEventArgs e) + { + if (game.PreviousGameState is not null + && ((game.CurrentTurnWhite && !whiteIsComputer) || (!game.CurrentTurnWhite && !blackIsComputer))) + { + game = game.PreviousGameState; + if (whiteIsComputer || blackIsComputer) + { + // Reverse two moves if the opponent is computer controlled + game = game.PreviousGameState!; + } + UpdateGameDisplay(); + await CheckComputerMove(); + } + } + private void whiteDepthBackingSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { if (!updateDepthSliders)