reintroduce microsoft login. upgrade a bunch of stuff.

This commit is contained in:
2023-01-19 16:20:41 -06:00
parent 2a423bcb93
commit 1d0beaf69f
29 changed files with 601 additions and 483 deletions

View File

@@ -0,0 +1,11 @@
@using Contracts.Types;
<GameBoardPresentation Perspective="WhichPlayer.Player1" />
@code {
protected override void OnInitialized()
{
base.OnInitialized();
Console.WriteLine("Empty Game Board.");
}
}

View File

@@ -0,0 +1,45 @@
@using Shogi.Contracts.Api
@using Shogi.Contracts.Types;
@using System.Text.RegularExpressions;
@inject IShogiApi ShogiApi
@inject AccountState Account;
@inject PromotePrompt PromotePrompt;
@if (session == null)
{
<EmptyGameBoard />
}
else if (isSpectating)
{
<SpectatorGameBoard Session="session" />
}
else
{
<SeatedGameBoard Perspective="perspective" Session="session" />
}
@code {
[Parameter]
public string? SessionName { get; set; }
Session? session;
private WhichPlayer perspective;
private bool isSpectating;
protected override async Task OnParametersSetAsync()
{
if (!string.IsNullOrWhiteSpace(SessionName))
{
this.session = await ShogiApi.GetSession(SessionName);
if (this.session != null)
{
var accountId = Account.User?.Id;
this.perspective = accountId == session.Player2 ? WhichPlayer.Player2 : WhichPlayer.Player1;
this.isSpectating = !(accountId == this.session.Player1 || accountId == this.session.Player2);
Console.WriteLine($"IsSpectating - {isSpectating}. AccountId - {accountId}. Player1 - {this.session.Player1}. Player2 - {this.session.Player2}");
}
}
}
}

View File

@@ -0,0 +1,116 @@
@using Shogi.Contracts.Types;
@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];
var isSelected = piece != null && SelectedPosition == position;
<div class="tile" @onclick="OnClickTileInternal(piece, position)"
data-position="@(position)"
data-selected="@(isSelected)"
style="grid-area: @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="OnClickHandInternal(piece)">
<GamePiece Piece="piece" Perspective="Perspective" />
</div>
}
</div>
</aside>
}
</article>
@code {
[Parameter] public WhichPlayer Perspective { get; set; }
[Parameter] public Session? Session { get; set; }
[Parameter] public string? SelectedPosition { get; set; }
// TODO: Exchange these OnClick actions for events like "SelectionChangedEvent" and "MoveFromBoardEvent" and "MoveFromHandEvent".
[Parameter] public Action<Piece?, string>? OnClickTile { get; set; }
[Parameter] public Action<Piece>? OnClickHand { get; set; }
static readonly string[] Files = new[] { "A", "B", "C", "D", "E", "F", "G", "H", "I" };
private 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;
}
}
private Action OnClickTileInternal(Piece? piece, string position) => () => OnClickTile?.Invoke(piece, position);
private Action OnClickHandInternal(Piece piece) => () => OnClickHand?.Invoke(piece);
}

View File

@@ -0,0 +1,112 @@
.game-board {
display: grid;
grid-template-areas: "board side-board";
grid-template-columns: 3fr minmax(10rem, 1fr);
gap: 0.5rem;
background-color: #444;
}
.board {
grid-area: board;
}
.side-board {
grid-area: side-board;
}
.board {
position: relative;
display: grid;
grid-template-areas:
"rank A9 B9 C9 D9 E9 F9 G9 H9 I9"
"rank A8 B8 C8 D8 E8 F8 G8 H8 I8"
"rank A7 B7 C7 D7 E7 F7 G7 H7 I7"
"rank A6 B6 C6 D6 E6 F6 G6 H6 I6"
"rank A5 B5 C5 D5 E5 F5 G5 H5 I5"
"rank A4 B4 C4 D4 E4 F4 G4 H4 I4"
"rank A3 B3 C3 D3 E3 F3 G3 H3 I3"
"rank A2 B2 C2 D2 E2 F2 G2 H2 I2"
"rank A1 B1 C1 D1 E1 F1 G1 H1 I1"
". file file file file file file file file file";
grid-template-columns: auto repeat(9, minmax(0, 1fr));
grid-template-rows: repeat(9, minmax(0, 1fr)) auto;
max-height: calc(100vh - 3rem);
width: calc(100vmin * 0.9167);
aspect-ratio: 0.9167;
gap: 3px;
}
.board[data-perspective="Player2"] {
grid-template-areas:
"file file file file file file file file file ."
"I1 H1 G1 F1 E1 D1 C1 B1 A1 rank"
"I2 H2 G2 F2 E2 D2 C2 B2 A2 rank"
"I3 H3 G3 F3 E3 D3 C3 B3 A3 rank"
"I4 H4 G4 F4 E4 D4 C4 B4 A4 rank"
"I5 H5 G5 F5 E5 D5 C5 B5 A5 rank"
"I6 H6 G6 F6 E6 D6 C6 B6 A6 rank"
"I7 H7 G7 F7 E7 D7 C7 B7 A7 rank"
"I8 H8 G8 F8 E8 D8 C8 B8 A8 rank"
"I9 H9 G9 F9 E9 D9 C9 B9 A9 rank";
grid-template-columns: repeat(9, minmax(0, 1fr)) auto;
grid-template-rows: auto repeat(9, minmax(0, 1fr));
}
.tile {
background-color: beige;
display: grid;
place-content: center;
padding: 0.25rem;
overflow: hidden; /* Because SVGs are shaped weird */
transition: filter linear 0.25s;
}
.tile[data-selected] {
filter: invert(0.8);
}
.ruler {
color: beige;
display: flex;
flex-direction: row;
justify-content: space-around;
}
.ruler.vertical {
flex-direction: column;
}
.board[data-perspective="Player2"] .ruler {
flex-direction: row-reverse;
}
.board[data-perspective="Player2"] .ruler.vertical {
flex-direction: column-reverse;
}
.side-board {
display: grid;
grid-template-rows: auto 1fr auto;
}
.side-board .hand {
display: flex;
flex-wrap: wrap;
}
.promote-prompt {
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border: 2px solid #444;
background-color: #eaeaea;
padding: 1rem;
box-shadow: 1px 1px 1px #444;
text-align: center;
}
.promote-prompt[data-visible="true"] {
display: block;
}

View File

@@ -0,0 +1,71 @@
@using Shogi.Contracts.Api;
@using Shogi.Contracts.Types;
@using System.Text.RegularExpressions;
@inject PromotePrompt PromotePrompt;
@inject IShogiApi ShogiApi;
<GameBoardPresentation OnClickHand="OnClickHand" OnClickTile="OnClickTile" Session="Session" Perspective="Perspective" />
@code {
[Parameter] public WhichPlayer Perspective { get; set; }
[Parameter] public Session Session { get; set; }
private bool IsMyTurn => Session?.BoardState.WhoseTurn == Perspective;
private string? selectedBoardPosition;
private WhichPiece? selectedPieceFromHand;
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 (!IsMyTurn) return;
if (selectedBoardPosition == null || piece?.Owner == Perspective)
{
// Select a position.
selectedBoardPosition = position;
return;
}
if (selectedBoardPosition == position)
{
// Deselect the selected position.
selectedBoardPosition = null;
return;
}
if (piece == null)
{
if (ShouldPromptForPromotion(position) || ShouldPromptForPromotion(selectedBoardPosition))
{
PromotePrompt.Show(Session.SessionName, new MovePieceCommand
{
From = selectedBoardPosition,
To = position
});
}
else
{
await ShogiApi.Move(Session.SessionName, new MovePieceCommand
{
From = selectedBoardPosition,
IsPromotion = false,
To = position
});
}
}
}
void OnClickHand(Piece piece)
{
selectedPieceFromHand = piece.WhichPiece;
}
}

View File

@@ -0,0 +1,8 @@
@using Contracts.Types;
<p>You are spectating</p>
<GameBoardPresentation Perspective="WhichPlayer.Player1" Session="Session" />
@code {
[Parameter] public Session Session { get; set; }
}