161 lines
4.5 KiB
Plaintext
161 lines
4.5 KiB
Plaintext
@using Shogi.Contracts.Api;
|
|
@using Shogi.Contracts.Types;
|
|
@using System.Text.RegularExpressions;
|
|
@using System.Net;
|
|
@inject ShogiApi ShogiApi;
|
|
|
|
<div style="position: relative;">
|
|
<GameBoardPresentation Session="Session"
|
|
Perspective="Perspective"
|
|
OnClickHand="OnClickHand"
|
|
OnClickTile="OnClickTile"
|
|
SelectedPosition="@selectedBoardPosition"
|
|
SelectedPieceFromHand="@selectedPieceFromHand"
|
|
IsMyTurn="IsMyTurn" />
|
|
|
|
@if (showPromotePrompt)
|
|
{
|
|
<!-- Promote prompt -->
|
|
<!-- TODO: Add a background div which prevents mouse inputs to the board while this decision is being made. -->
|
|
<section class="promote-prompt">
|
|
<p>Do you wish to promote?</p>
|
|
<div>
|
|
<button type="button" @onclick="() => OnClickPromotionChoice(true)">Yes</button>
|
|
<button type="button" @onclick="() => OnClickPromotionChoice(false)">No</button>
|
|
<button type="button" @onclick="() => showPromotePrompt = false">Cancel</button>
|
|
</div>
|
|
</section>
|
|
}
|
|
</div>
|
|
|
|
@code {
|
|
[Parameter, EditorRequired]
|
|
public WhichPlayer Perspective { get; set; }
|
|
[Parameter, EditorRequired]
|
|
public Session Session { get; set; } = default!;
|
|
private bool IsMyTurn => Session?.BoardState.WhoseTurn == Perspective;
|
|
private string? selectedBoardPosition;
|
|
private WhichPiece? selectedPieceFromHand;
|
|
private bool showPromotePrompt;
|
|
private string? moveTo;
|
|
|
|
protected override void OnParametersSet()
|
|
{
|
|
base.OnParametersSet();
|
|
selectedBoardPosition = null;
|
|
selectedPieceFromHand = null;
|
|
if (Session == null)
|
|
{
|
|
throw new ArgumentException($"{nameof(Session)} cannot be null.", nameof(Session));
|
|
}
|
|
}
|
|
|
|
bool IsWithinPromoteArea(string position)
|
|
{
|
|
if (Perspective == WhichPlayer.Player1 && Regex.IsMatch(position, ".[7-9]"))
|
|
{
|
|
return true;
|
|
}
|
|
if (Perspective == WhichPlayer.Player2 && Regex.IsMatch(position, ".[1-3]"))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
async Task OnClickTile(string position)
|
|
{
|
|
if (!IsMyTurn || showPromotePrompt) return;
|
|
|
|
var pieceAtPosition = Session.BoardState.Board[position];
|
|
if (selectedBoardPosition == position)
|
|
{
|
|
// Deselect the selected position.
|
|
selectedBoardPosition = null;
|
|
StateHasChanged();
|
|
return;
|
|
}
|
|
|
|
if (selectedBoardPosition == null && pieceAtPosition?.Owner == Perspective)
|
|
{
|
|
// Select an owned piece.
|
|
selectedBoardPosition = position;
|
|
// Prevent selecting pieces from the hand and board at the same time.
|
|
selectedPieceFromHand = null;
|
|
StateHasChanged();
|
|
return;
|
|
}
|
|
|
|
if (selectedPieceFromHand is not null)
|
|
{
|
|
if (pieceAtPosition is null)
|
|
{
|
|
// Placing a piece from the hand to an empty space.
|
|
var success = await ShogiApi.Move(
|
|
Session.SessionId,
|
|
new MovePieceCommand(selectedPieceFromHand.Value, position));
|
|
if (!success)
|
|
{
|
|
selectedPieceFromHand = null;
|
|
}
|
|
}
|
|
StateHasChanged();
|
|
return;
|
|
}
|
|
|
|
if (selectedBoardPosition != null)
|
|
{
|
|
if (pieceAtPosition == null || pieceAtPosition?.Owner != Perspective)
|
|
{
|
|
var pieceBeingMoved = Session.BoardState.Board[selectedBoardPosition];
|
|
var isPromotedAlready = pieceBeingMoved != null && pieceBeingMoved.IsPromoted;
|
|
Console.WriteLine("Is promoted? {0}", isPromotedAlready);
|
|
// Moving to an empty space or capturing an opponent's piece.
|
|
if (!isPromotedAlready && (IsWithinPromoteArea(position) || IsWithinPromoteArea(selectedBoardPosition)))
|
|
{
|
|
Console.WriteLine("Prompt!");
|
|
moveTo = position;
|
|
showPromotePrompt = true;
|
|
}
|
|
else
|
|
{
|
|
var success = await ShogiApi.Move(Session.SessionId, new MovePieceCommand(selectedBoardPosition, position, false));
|
|
if (!success)
|
|
{
|
|
selectedBoardPosition = null;
|
|
}
|
|
}
|
|
StateHasChanged();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void OnClickHand(Piece piece)
|
|
{
|
|
if (!IsMyTurn || showPromotePrompt) return;
|
|
|
|
// Prevent selecting from both the hand and the board.
|
|
selectedBoardPosition = null;
|
|
|
|
selectedPieceFromHand = piece.WhichPiece == selectedPieceFromHand
|
|
// Deselecting the already-selected piece
|
|
? selectedPieceFromHand = null
|
|
: selectedPieceFromHand = piece.WhichPiece;
|
|
|
|
StateHasChanged();
|
|
}
|
|
|
|
private async Task OnClickPromotionChoice(bool shouldPromote)
|
|
{
|
|
if (selectedBoardPosition != null && moveTo != null)
|
|
{
|
|
await ShogiApi.Move(Session.SessionId, new MovePieceCommand(selectedBoardPosition, moveTo, shouldPromote));
|
|
showPromotePrompt = false;
|
|
return;
|
|
}
|
|
|
|
throw new InvalidOperationException("Unexpected scenario during OnClickPromotionChoice.");
|
|
}
|
|
}
|