diff --git a/CustomGame.xaml.cs b/CustomGame.xaml.cs
index 1ffb741..922e952 100644
--- a/CustomGame.xaml.cs
+++ b/CustomGame.xaml.cs
@@ -125,7 +125,7 @@ private void startButton_Click(object sender, RoutedEventArgs e)
bool currentTurnSente = turnSelectSente.IsChecked ?? false;
GeneratedGame = new ShogiGame(Board, currentTurnSente,
ShogiGame.EndingStates.Contains(BoardAnalysis.DetermineGameState(Board, currentTurnSente)),
- new(), new(), new(), sentePieceDrops, gotePieceDrops, new(), null);
+ new(), new(), new(), sentePieceDrops, gotePieceDrops, new(), null, null);
Close();
}
diff --git a/MainWindow.xaml b/MainWindow.xaml
index 64ba837..f9e6933 100644
--- a/MainWindow.xaml
+++ b/MainWindow.xaml
@@ -30,6 +30,8 @@
+
+
diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs
index 7552957..f942b9d 100644
--- a/MainWindow.xaml.cs
+++ b/MainWindow.xaml.cs
@@ -979,6 +979,22 @@ private void NotationSetItem_Click(object sender, RoutedEventArgs e)
UpdateGameDisplay();
}
+ private async void UndoMove_Click(object sender, RoutedEventArgs e)
+ {
+ if (game.PreviousGameState is not null
+ && ((game.CurrentTurnSente && !senteIsComputer) || (!game.CurrentTurnSente && !goteIsComputer)))
+ {
+ game = game.PreviousGameState;
+ if (senteIsComputer || goteIsComputer)
+ {
+ // Reverse two moves if the opponent is computer controlled
+ game = game.PreviousGameState!;
+ }
+ UpdateGameDisplay();
+ await CheckComputerMove();
+ }
+ }
+
private void GoteDrop_MouseUp(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left && !game.GameOver)
diff --git a/ShogiGame.cs b/ShogiGame.cs
index 5ebf33c..5b76702 100644
--- a/ShogiGame.cs
+++ b/ShogiGame.cs
@@ -77,6 +77,7 @@ public class ShogiGame
public List<(string, Point, Point, bool, bool)> Moves { get; }
public List JapaneseMoveText { get; }
public List WesternMoveText { get; }
+ public ShogiGame? PreviousGameState { get; private set; }
public Dictionary SentePieceDrops { get; }
public Dictionary GotePieceDrops { get; }
@@ -155,7 +156,7 @@ public ShogiGame(Pieces.Piece?[,] board, bool currentTurnSente, bool gameOver,
List<(string, Point, Point, bool, bool)> moves, List japaneseMoveText,
List westernMoveText, Dictionary? sentePieceDrops,
Dictionary? gotePieceDrops, Dictionary boardCounts,
- string? initialState)
+ string? initialState, ShogiGame? previousGameState)
{
if (board.GetLength(0) is not 9 and not 5 || board.GetLength(1) is not 9 and not 5)
{
@@ -198,6 +199,7 @@ public ShogiGame(Pieces.Piece?[,] board, bool currentTurnSente, bool gameOver,
BoardCounts = boardCounts;
InitialState = initialState ?? ToString();
+ PreviousGameState = previousGameState;
}
///
@@ -216,7 +218,7 @@ public ShogiGame Clone()
return new ShogiGame(boardClone, CurrentTurnSente, GameOver, new(Moves), new(JapaneseMoveText),
new(WesternMoveText), new Dictionary(SentePieceDrops),
- new Dictionary(GotePieceDrops), new(BoardCounts), InitialState);
+ new Dictionary(GotePieceDrops), new(BoardCounts), InitialState, PreviousGameState?.Clone());
}
///
@@ -348,7 +350,7 @@ public bool IsDropPossible(Type dropType, Point destination)
/// If a piece can be promoted, should it be? means the user should be prompted.
///
///
- /// 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
@@ -393,11 +395,12 @@ public bool MovePiece(Point source, Point destination, bool forceMove = false, b
}
}
- // Used for generating new move text
+ // Used for generating new move text and move undoing
ShogiGame? oldGame = null;
if (updateMoveText)
{
oldGame = Clone();
+ PreviousGameState = oldGame;
}
bool pieceMoved = piece.Move(Board, destination, forceMove || source.X == -1);
@@ -976,7 +979,7 @@ public static ShogiGame FromShogiForsythEdwards(string forsythEdwards)
// Shogi Forsyth–Edwards doesn't define what the previous moves were, so they moves list starts empty
return new ShogiGame(board, currentTurnSente, EndingStates.Contains(BoardAnalysis.DetermineGameState(board, currentTurnSente)),
- new(), new(), new(), sentePieceDrops, gotePieceDrops, new(), null);
+ new(), new(), new(), sentePieceDrops, gotePieceDrops, new(), null, null);
}
}
}