diff --git a/CustomGame.xaml.cs b/CustomGame.xaml.cs index 31c9db7..f3a570d 100644 --- a/CustomGame.xaml.cs +++ b/CustomGame.xaml.cs @@ -115,7 +115,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(), sentePieceDrops, gotePieceDrops, new(), null); + new(), new(), new(), sentePieceDrops, gotePieceDrops, new(), null); Close(); } diff --git a/MainWindow.xaml b/MainWindow.xaml index 53accc2..275066f 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -39,6 +39,10 @@ + + + + diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 5161d29..79d1ee1 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -62,6 +62,10 @@ public MainWindow() { item.IsChecked = config.PieceSet == (string)item.Tag; } + foreach (MenuItem item in notationSetItem.Items) + { + item.IsChecked = config.Notation == (string)item.Tag; + } } public void UpdateGameDisplay() @@ -215,9 +219,12 @@ public void UpdateGameDisplay() } movesPanel.Children.Clear(); - for (int i = 0; i < game.MoveText.Count; i++) + List moves = config.Notation == "western" + ? game.WesternMoveText + : game.JapaneseMoveText; + for (int i = 0; i < moves.Count; i++) { - string text = $"{i + 1}. {game.MoveText[i]}"; + string text = $"{i + 1}. {moves[i]}"; _ = movesPanel.Children.Add(new Label() { Content = text, @@ -495,7 +502,7 @@ private void UpdateEvaluationMeter(BoardAnalysis.PossibleMove? bestMove, bool se foreach ((System.Drawing.Point source, System.Drawing.Point destination, bool doPromotion) in bestMove.Value.BestLine) { _ = moveStringGenerator.MovePiece(source, destination, true, doPromotion); - convertedBestLine += " " + moveStringGenerator.MoveText[^1]; + convertedBestLine += " " + moveStringGenerator.JapaneseMoveText[^1]; } toUpdate.ToolTip = convertedBestLine.Trim(); } @@ -887,6 +894,17 @@ private void PieceSetItem_Click(object sender, RoutedEventArgs e) UpdateGameDisplay(); } + private void NotationSetItem_Click(object sender, RoutedEventArgs e) + { + string chosenNotation = (string)((MenuItem)sender).Tag; + config.Notation = chosenNotation; + foreach (MenuItem item in notationSetItem.Items) + { + item.IsChecked = chosenNotation == (string)item.Tag; + } + UpdateGameDisplay(); + } + private void GoteDrop_MouseUp(object sender, MouseButtonEventArgs e) { if (e.ChangedButton == MouseButton.Left && !game.GameOver) diff --git a/Settings.cs b/Settings.cs index 1a20804..d82cf67 100644 --- a/Settings.cs +++ b/Settings.cs @@ -10,6 +10,7 @@ public class Settings public bool FlipBoard { get; set; } public bool UpdateEvalAfterBot { get; set; } public string PieceSet { get; set; } + public string Notation { get; set; } public Color BoardColor { get; set; } public Color CheckedKingColor { get; set; } @@ -27,6 +28,7 @@ public Settings() FlipBoard = false; UpdateEvalAfterBot = true; PieceSet = "1kanji"; + Notation = "japanese"; BoardColor = Color.FromRgb(249, 184, 83); CheckedKingColor = Brushes.Red.Color; @@ -41,7 +43,7 @@ public Settings() } [JsonConstructor] - public Settings(bool flipBoard, bool updateEvalAfterBot, string pieceSet, + public Settings(bool flipBoard, bool updateEvalAfterBot, string pieceSet, string notation, Color boardColor, Color checkedKingColor, Color selectedPieceColor, Color checkMateHighlightColor, Color lastMoveSourceColor, Color lastMoveDestinationColor, Color bestMoveSourceColor, Color bestMoveDestinationColor, Color availableMoveColor, Color availableCaptureColor) @@ -49,6 +51,7 @@ public Settings(bool flipBoard, bool updateEvalAfterBot, string pieceSet, FlipBoard = flipBoard; UpdateEvalAfterBot = updateEvalAfterBot; PieceSet = pieceSet; + Notation = notation; BoardColor = boardColor; CheckedKingColor = checkedKingColor; SelectedPieceColor = selectedPieceColor; diff --git a/ShogiGame.cs b/ShogiGame.cs index db555a8..c913642 100644 --- a/ShogiGame.cs +++ b/ShogiGame.cs @@ -72,7 +72,8 @@ public class ShogiGame /// (pieceLetter, sourcePosition, destinationPosition, promotionHappened, dropHappened) /// public List<(string, Point, Point, bool, bool)> Moves { get; } - public List MoveText { get; } + public List JapaneseMoveText { get; } + public List WesternMoveText { get; } public Dictionary SentePieceDrops { get; } public Dictionary GotePieceDrops { get; } @@ -92,7 +93,8 @@ public ShogiGame() GoteKing = new Pieces.King(new Point(4, 8), false); Moves = new List<(string, Point, Point, bool, bool)>(); - MoveText = new List(); + JapaneseMoveText = new List(); + WesternMoveText = new List(); SentePieceDrops = new Dictionary() { { typeof(Pieces.GoldGeneral), 0 }, @@ -136,9 +138,10 @@ public ShogiGame() /// Create a new instance of a shogi game, setting each game parameter to a non-default value /// public ShogiGame(Pieces.Piece?[,] board, bool currentTurnSente, bool gameOver, - List<(string, Point, Point, bool, bool)> moves, List moveText, - Dictionary? sentePieceDrops, Dictionary? gotePieceDrops, - Dictionary boardCounts, string? initialState) + List<(string, Point, Point, bool, bool)> moves, List japaneseMoveText, + List westernMoveText, Dictionary? sentePieceDrops, + Dictionary? gotePieceDrops, Dictionary boardCounts, + string? initialState) { if (board.GetLength(0) != 9 || board.GetLength(1) != 9) { @@ -152,7 +155,8 @@ public ShogiGame(Pieces.Piece?[,] board, bool currentTurnSente, bool gameOver, CurrentTurnSente = currentTurnSente; GameOver = gameOver; Moves = moves; - MoveText = moveText; + JapaneseMoveText = japaneseMoveText; + WesternMoveText = westernMoveText; SentePieceDrops = sentePieceDrops ?? new Dictionary() { { typeof(Pieces.GoldGeneral), 0 }, @@ -192,9 +196,9 @@ public ShogiGame Clone() } } - return new ShogiGame(boardClone, CurrentTurnSente, GameOver, new(Moves), new(MoveText), - new Dictionary(SentePieceDrops), new Dictionary(GotePieceDrops), - new(BoardCounts), InitialState); + return new ShogiGame(boardClone, CurrentTurnSente, GameOver, new(Moves), new(JapaneseMoveText), + new(WesternMoveText), new Dictionary(SentePieceDrops), + new Dictionary(GotePieceDrops), new(BoardCounts), InitialState); } /// @@ -460,52 +464,61 @@ public bool MovePiece(Point source, Point destination, bool forceMove = false, b if (updateMoveText) { - string newMove = (CurrentTurnSente ? "☖" : "☗") + string newJapaneseMove = (CurrentTurnSente ? "☖" : "☗") + (Moves.Count > 1 && destination == Moves[^2].Item3 ? "同 " : destination.ToShogiCoordinate()) + beforePromotion.SymbolLetter; + string newWesternMove = beforePromotion.SFENLetter; // Disambiguate moving piece if two pieces of the same type can reach destination IEnumerable canReachDest = oldGame!.Board.OfType().Where( - p => piece.GetType() == p.GetType() && p.Position != source && p.IsSente == piece.IsSente + p => beforePromotion.GetType() == p.GetType() && p.Position != source && p.IsSente == beforePromotion.IsSente && p.GetValidMoves(oldGame.Board, true).Contains(destination)); if (canReachDest.Any()) { + newWesternMove += $"{9 - source.X}{9 - source.Y}"; if (source.X == -1) { - newMove += '打'; + newJapaneseMove += '打'; } else if (destination.Y > source.Y && !canReachDest.Where(p => destination.Y > p.Position.Y).Any()) { - newMove += CurrentTurnSente ? '引' : '上'; + newJapaneseMove += CurrentTurnSente ? '引' : '上'; } else if (destination.Y < source.Y && !canReachDest.Where(p => destination.Y < p.Position.Y).Any()) { - newMove += CurrentTurnSente ? '上' : '引'; + newJapaneseMove += CurrentTurnSente ? '上' : '引'; } else if (destination.Y == source.Y && !canReachDest.Where(p => destination.Y == p.Position.Y).Any()) { - newMove += '寄'; + newJapaneseMove += '寄'; } else if (destination.X > source.X && !canReachDest.Where(p => destination.X > p.Position.X).Any()) { - newMove += CurrentTurnSente ? "右" : "左"; + newJapaneseMove += CurrentTurnSente ? "右" : "左"; } else if (destination.X < source.X && !canReachDest.Where(p => destination.X < p.Position.X).Any()) { - newMove += CurrentTurnSente ? "左" : "右"; + newJapaneseMove += CurrentTurnSente ? "左" : "右"; } else { - newMove += "直"; + newJapaneseMove += "直"; } } + newWesternMove += source.X == -1 ? '*' + : oldGame.Board[destination.X, destination.Y] is not null ? 'x' + : '-'; + newWesternMove += $"{9 - destination.X}{9 - destination.Y}"; + if (promotionPossible) { - newMove += promotionHappened ? "成" : "不成"; + newJapaneseMove += promotionHappened ? "成" : "不成"; + newWesternMove += promotionHappened ? '+' : '='; } - MoveText.Add(newMove); + JapaneseMoveText.Add(newJapaneseMove); + WesternMoveText.Add(newWesternMove); } return true; @@ -937,7 +950,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(), sentePieceDrops, gotePieceDrops, new(), null); + new(), new(), new(), sentePieceDrops, gotePieceDrops, new(), null); } } }