diff --git a/Shogi.Api/Controllers/SessionsController.cs b/Shogi.Api/Controllers/SessionsController.cs index b690410..82aa771 100644 --- a/Shogi.Api/Controllers/SessionsController.cs +++ b/Shogi.Api/Controllers/SessionsController.cs @@ -67,7 +67,10 @@ public class SessionsController( Player1Hand = session.Board.BoardState.Player1Hand.ToContract(), Player2Hand = session.Board.BoardState.Player2Hand.ToContract(), PlayerInCheck = session.Board.BoardState.InCheck?.ToContract(), - WhoseTurn = session.Board.BoardState.WhoseTurn.ToContract() + WhoseTurn = session.Board.BoardState.WhoseTurn.ToContract(), + Victor = session.Board.BoardState.IsCheckmate + ? session.Board.BoardState.InCheck == Domain.ValueObjects.WhichPlayer.Player1 ? WhichPlayer.Player2 : WhichPlayer.Player1 + : null }, Player1 = application.GetUsername(session.Player1), Player2 = application.GetUsername(session.Player2), diff --git a/Shogi.Contracts/Types/BoardState.cs b/Shogi.Contracts/Types/BoardState.cs index fee2145..ef9b987 100644 --- a/Shogi.Contracts/Types/BoardState.cs +++ b/Shogi.Contracts/Types/BoardState.cs @@ -1,14 +1,14 @@ using System; using System.Collections.Generic; -namespace Shogi.Contracts.Types +namespace Shogi.Contracts.Types; + +public class BoardState { - public class BoardState - { - public Dictionary Board { get; set; } = new Dictionary(); - public IReadOnlyCollection Player1Hand { get; set; } = Array.Empty(); - public IReadOnlyCollection Player2Hand { get; set; } = Array.Empty(); - public WhichPlayer? PlayerInCheck { get; set; } - public WhichPlayer WhoseTurn { get; set; } - } + public Dictionary Board { get; set; } = new Dictionary(); + public IReadOnlyCollection Player1Hand { get; set; } = Array.Empty(); + public IReadOnlyCollection Player2Hand { get; set; } = Array.Empty(); + public WhichPlayer? PlayerInCheck { get; set; } + public WhichPlayer WhoseTurn { get; set; } + public WhichPlayer? Victor { get; set; } } diff --git a/Shogi.Domain/ValueObjects/ShogiBoard.cs b/Shogi.Domain/ValueObjects/ShogiBoard.cs index 74356c6..8fe4ade 100644 --- a/Shogi.Domain/ValueObjects/ShogiBoard.cs +++ b/Shogi.Domain/ValueObjects/ShogiBoard.cs @@ -91,6 +91,11 @@ public sealed class ShogiBoard(BoardState initialState) public MoveResult Move(WhichPiece pieceInHand, string to) { + if (BoardState.IsCheckmate) + { + return new MoveResult(false, "The game is over. A winner has been decided."); + } + var index = BoardState.ActivePlayerHand.FindIndex(p => p.WhichPiece == pieceInHand); if (index == -1) { @@ -250,7 +255,8 @@ public sealed class ShogiBoard(BoardState initialState) list.Add(position); position += path.Step; } - } else if (position.IsInsideBoardBoundary()) + } + else if (position.IsInsideBoardBoundary()) { list.Add(position); } diff --git a/Shogi.UI/Pages/Play/GameBoard/GameBoardPresentation.razor b/Shogi.UI/Pages/Play/GameBoard/GameBoardPresentation.razor index d069266..a7c180a 100644 --- a/Shogi.UI/Pages/Play/GameBoard/GameBoardPresentation.razor +++ b/Shogi.UI/Pages/Play/GameBoard/GameBoardPresentation.razor @@ -2,14 +2,6 @@ @using System.Text.Json;
- @if (IsSpectating) - { - - }
@for (var rank = 1; rank < 10; rank++) @@ -74,13 +66,13 @@
- +
- +
- @if (string.IsNullOrEmpty(Session.Player2) && !string.IsNullOrEmpty(Session.Player1)) + @if (Perspective == WhichPlayer.Player2 && string.IsNullOrEmpty(Session.Player2)) {
@@ -172,6 +164,11 @@ private bool IsOpponentInCheck => Session?.BoardState.PlayerInCheck != null && Session.BoardState.PlayerInCheck != Perspective; + private bool IsPlayerVictor => Session?.BoardState.Victor == Perspective; + + + private bool IsOpponentVictor => Session?.BoardState.Victor != null && Session.BoardState.Victor != Perspective; + private Func OnClickTileInternal(string position) => () => { if (IsMyTurn) diff --git a/Shogi.UI/Pages/Play/GameBoard/PlayerName.razor b/Shogi.UI/Pages/Play/GameBoard/PlayerName.razor index d0a9c2c..8eda863 100644 --- a/Shogi.UI/Pages/Play/GameBoard/PlayerName.razor +++ b/Shogi.UI/Pages/Play/GameBoard/PlayerName.razor @@ -11,6 +11,12 @@   } + @if (IsVictor) + { + Victor +   + } + @if (string.IsNullOrEmpty(Name)) { Empty Seat @@ -25,5 +31,6 @@ @code { [Parameter][EditorRequired] public bool IsTurn { get; set; } [Parameter][EditorRequired] public bool InCheck { get; set; } + [Parameter][EditorRequired] public bool IsVictor { get; set; } [Parameter][EditorRequired] public string Name { get; set; } = string.Empty; } diff --git a/Shogi.UI/Pages/Play/GameBoard/PlayerName.razor.css b/Shogi.UI/Pages/Play/GameBoard/PlayerName.razor.css index 9be37f4..4b93c20 100644 --- a/Shogi.UI/Pages/Play/GameBoard/PlayerName.razor.css +++ b/Shogi.UI/Pages/Play/GameBoard/PlayerName.razor.css @@ -15,3 +15,12 @@ font-weight: bold; font-size: 80%; } + +.victory-marker { + display: inline-block; + padding: 3px 8px; + background-color: darkgreen; + color: beige; + font-weight: bold; + font-size: 80%; +}