This commit is contained in:
2024-10-20 22:27:08 -05:00
parent f75553a0ad
commit 3593785421
27 changed files with 1020 additions and 1081 deletions

View File

@@ -5,7 +5,6 @@
@implements IDisposable
@inject ShogiApi ShogiApi
@inject PromotePrompt PromotePrompt
@inject GameHubNode hubNode
@inject NavigationManager navigator

View File

@@ -1,6 +1,5 @@
@using Shogi.Contracts.Types;
@using System.Text.Json;
@inject PromotePrompt PromotePrompt;
<article class="game-board">
@if (IsSpectating)
@@ -53,16 +52,6 @@
<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 -->
@@ -121,13 +110,6 @@
</article>
@code {
static readonly string[] Files = new[] { "A", "B", "C", "D", "E", "F", "G", "H", "I" };
/// <summary>

View File

@@ -110,20 +110,4 @@
grid-template-rows: 3rem;
place-items: center start;
padding: 0.5rem;
}
.promote-prompt {
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border: 2px solid #444;
padding: 1rem;
box-shadow: 1px 1px 1px #444;
text-align: center;
}
.promote-prompt[data-visible="true"] {
display: block;
}
}

View File

@@ -2,16 +2,31 @@
@using Shogi.Contracts.Types;
@using System.Text.RegularExpressions;
@using System.Net;
@inject PromotePrompt PromotePrompt;
@inject ShogiApi ShogiApi;
<GameBoardPresentation Session="Session"
Perspective="Perspective"
OnClickHand="OnClickHand"
OnClickTile="OnClickTile"
SelectedPosition="@selectedBoardPosition"
SelectedPieceFromHand="@selectedPieceFromHand"
IsMyTurn="IsMyTurn" />
<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]
@@ -21,6 +36,8 @@
private bool IsMyTurn => Session?.BoardState.WhoseTurn == Perspective;
private string? selectedBoardPosition;
private WhichPiece? selectedPieceFromHand;
private bool showPromotePrompt;
private string? moveTo;
protected override void OnParametersSet()
{
@@ -75,7 +92,7 @@
{
// Placing a piece from the hand to an empty space.
var success = await ShogiApi.Move(
Session.SessionId.ToString(),
Session.SessionId,
new MovePieceCommand(selectedPieceFromHand.Value, position));
if (!success)
{
@@ -88,18 +105,24 @@
if (selectedBoardPosition != null)
{
Console.WriteLine("pieceAtPosition is null? {0}", pieceAtPosition == null);
if (pieceAtPosition == null || pieceAtPosition?.Owner != Perspective)
{
// Moving to an empty space or capturing an opponent's piece.
if (ShouldPromptForPromotion(position) || ShouldPromptForPromotion(selectedBoardPosition))
{
PromotePrompt.Show(
Session.SessionId.ToString(),
new MovePieceCommand(selectedBoardPosition, position, false));
Console.WriteLine("Prompt!");
moveTo = position;
showPromotePrompt = true;
}
else
{
var success = await ShogiApi.Move(Session.SessionId.ToString(), new MovePieceCommand(selectedBoardPosition, position, false));
Console.WriteLine("OnClick to move to {0}", position);
var success = await ShogiApi.Move(Session.SessionId, new MovePieceCommand(selectedBoardPosition, position, false));
Console.WriteLine("Success? {0}", success);
if (!success)
{
selectedBoardPosition = null;
@@ -125,4 +148,14 @@
StateHasChanged();
}
private Task OnClickPromotionChoice(bool shouldPromote)
{
if (selectedBoardPosition == null && selectedPieceFromHand.HasValue && moveTo != null)
{
return ShogiApi.Move(Session.SessionId, new MovePieceCommand(selectedPieceFromHand.Value, moveTo));
}
throw new InvalidOperationException("Unexpected scenario during OnClickPromotionChoice.");
}
}

View File

@@ -0,0 +1,14 @@
.promote-prompt {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border: 2px solid #444;
padding: 1rem;
box-shadow: 1px 1px 1px #444;
text-align: center;
z-index: 101;
background-color: #444;
border: 1px solid black;
}

View File

@@ -1,58 +0,0 @@
using Shogi.Contracts.Api;
using Shogi.UI.Shared;
namespace Shogi.UI.Pages.Play;
public class PromotePrompt
{
private readonly ShogiApi shogiApi;
private string? sessionName;
private MovePieceCommand? command;
public PromotePrompt(ShogiApi shogiApi)
{
this.shogiApi = shogiApi;
this.IsVisible = false;
this.OnClickCancel = this.Hide;
}
public bool IsVisible { get; private set; }
public Action OnClickCancel;
public Func<Task>? OnClickNo;
public Func<Task>? OnClickYes;
public void Show(string sessionName, MovePieceCommand command)
{
this.sessionName = sessionName;
this.command = command;
this.IsVisible = true;
this.OnClickNo = this.Move;
this.OnClickYes = this.MoveAndPromote;
}
public void Hide()
{
this.IsVisible = false;
this.OnClickNo = null;
this.OnClickYes = null;
}
private Task Move()
{
if (this.command != null && this.sessionName != null)
{
this.command.IsPromotion = false;
return this.shogiApi.Move(this.sessionName, this.command);
}
return Task.CompletedTask;
}
private Task MoveAndPromote()
{
if (this.command != null && this.sessionName != null)
{
this.command.IsPromotion = true;
return this.shogiApi.Move(this.sessionName, this.command);
}
return Task.CompletedTask;
}
}

View File

@@ -39,8 +39,7 @@ static void ConfigureDependencies(IServiceCollection services, IConfiguration co
services
.AddTransient<CookieCredentialsMessageHandler>()
.AddTransient<ILocalStorage, LocalStorage>()
.AddSingleton<PromotePrompt>();
.AddTransient<ILocalStorage, LocalStorage>();
// Identity
services

View File

@@ -52,7 +52,7 @@ public class ShogiApi(HttpClient httpClient)
/// <summary>
/// Returns false if the move was not accepted by the server.
/// </summary>
public async Task<bool> Move(string sessionName, MovePieceCommand command)
public async Task<bool> Move(Guid sessionName, MovePieceCommand command)
{
var response = await httpClient.PatchAsync(Relative($"Sessions/{sessionName}/Move"), JsonContent.Create(command));
return response.IsSuccessStatusCode;