Files
Shogi/Shogi.UI/Pages/Home/GameBoard.razor

186 lines
5.4 KiB
Plaintext

@using Shogi.Contracts.Api
@using Shogi.Contracts.Types;
@using System.Text.RegularExpressions;
@inject IShogiApi ShogiApi
@inject AccountState Account;
@inject PromotePrompt PromotePrompt;
<article class="game-board">
<!-- Game board -->
<section class="board" data-perspective="@Perspective">
@for (var rank = 1; rank < 10; rank++)
{
foreach (var file in Files)
{
var position = $"{file}{rank}";
var piece = session?.BoardState.Board[position];
<div class="tile"
data-position="@(position)"
data-selected="@(piece != null && selectedPosition == position)"
style="grid-area: @(position)"
@onclick="() => OnClickTile(piece, position)">
<GamePiece Piece="piece" Perspective="Perspective" />
</div>
}
}
<div class="ruler vertical" style="grid-area: rank">
<span>9</span>
<span>8</span>
<span>7</span>
<span>6</span>
<span>5</span>
<span>4</span>
<span>3</span>
<span>2</span>
<span>1</span>
</div>
<div class="ruler" style="grid-area: file">
<span>A</span>
<span>B</span>
<span>C</span>
<span>D</span>
<span>E</span>
<span>F</span>
<span>G</span>
<span>H</span>
<span>I</span>
</div>
<!-- Promote prompt -->
<div class="promote-prompt" data-visible="@PromotePrompt.IsVisible">
<p>Do you wish to promote?</p>
<div>
<button type="button">Yes</button>
<button type="button">No</button>
<button type="button">Cancel</button>
</div>
</div>
</section>
<!-- Side board -->
@if (session != null)
{
<aside class="side-board">
<div class="hand">
@foreach (var piece in OpponentHand)
{
<div class="tile">
<GamePiece Piece="piece" Perspective="Perspective" />
</div>
}
</div>
<div class="spacer" />
<div class="hand">
@foreach (var piece in UserHand)
{
<div class="title" @onclick="() => OnClickHand(piece)">
<GamePiece Piece="piece" Perspective="Perspective" />
</div>
}
</div>
</aside>
}
</article>
@code {
static readonly string[] Files = new[] { "A", "B", "C", "D", "E", "F", "G", "H", "I" };
[Parameter]
public string? SessionName { get; set; }
WhichPlayer Perspective => Account.User?.Id == session?.Player1
? WhichPlayer.Player1
: WhichPlayer.Player2;
Session? session;
IReadOnlyCollection<Piece> OpponentHand
{
get
{
if (this.session == null) return Array.Empty<Piece>();
return Perspective == WhichPlayer.Player1
? this.session.BoardState.Player1Hand
: this.session.BoardState.Player2Hand;
}
}
IReadOnlyCollection<Piece> UserHand
{
get
{
if (this.session == null) return Array.Empty<Piece>();
return Perspective == WhichPlayer.Player1
? this.session.BoardState.Player1Hand
: this.session.BoardState.Player2Hand;
}
}
bool IsMyTurn => session?.BoardState.WhoseTurn == Perspective;
string? selectedPosition;
WhichPiece? selectedPiece;
protected override async Task OnParametersSetAsync()
{
if (!string.IsNullOrWhiteSpace(SessionName))
{
this.session = await ShogiApi.GetSession(SessionName);
}
}
bool ShouldPromptForPromotion(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 void OnClickTile(Piece? piece, string position)
{
if (SessionName == null || !IsMyTurn) return;
if (selectedPosition == null || piece?.Owner == Perspective)
{
// Select a position.
selectedPosition = position;
return;
}
if (selectedPosition == position)
{
// Deselect the selected position.
selectedPosition = null;
return;
}
if (piece == null)
{
if (ShouldPromptForPromotion(position) || ShouldPromptForPromotion(selectedPosition))
{
PromotePrompt.Show(SessionName, new MovePieceCommand
{
From = selectedPosition,
To = position
});
}
else
{
await ShogiApi.Move(SessionName, new MovePieceCommand
{
From = selectedPosition,
IsPromotion = false,
To = position
});
}
}
}
void OnClickHand(Piece piece)
{
selectedPiece = piece.WhichPiece;
}
}