Better communication
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
namespace Gameboard.ShogiUI.Sockets.ServiceModels.Socket.Types
|
||||
{
|
||||
public class Coords
|
||||
{
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,12 @@
|
||||
namespace Gameboard.ShogiUI.Sockets.ServiceModels.Socket.Types
|
||||
{
|
||||
public class Move
|
||||
{
|
||||
public string PieceFromCaptured { get; set; }
|
||||
public Coords From { get; set; }
|
||||
public Coords To { get; set; }
|
||||
public bool IsPromotion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Toggles perspective of this move. (ie from player 1 to player 2)
|
||||
/// </summary>
|
||||
public static Move ConvertPerspective(Move m)
|
||||
{
|
||||
var convertedMove = new Move
|
||||
{
|
||||
To = new Coords
|
||||
{
|
||||
X = 8 - m.To.X,
|
||||
Y = 8 - m.To.Y
|
||||
},
|
||||
From = new Coords
|
||||
{
|
||||
X = 8 - m.From.X,
|
||||
Y = 8 - m.From.Y
|
||||
},
|
||||
IsPromotion = m.IsPromotion,
|
||||
PieceFromCaptured = m.PieceFromCaptured
|
||||
};
|
||||
return convertedMove;
|
||||
}
|
||||
}
|
||||
public class Move
|
||||
{
|
||||
public string PieceFromCaptured { get; set; }
|
||||
/// <summary>Board position notation, like A3 or G1</summary>
|
||||
public string From { get; set; }
|
||||
/// <summary>Board position notation, like A3 or G1</summary>
|
||||
public string To { get; set; }
|
||||
public bool IsPromotion { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="5.10.3" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Gameboard.ShogiUI.Sockets.ServiceModels\Gameboard.ShogiUI.Sockets.ServiceModels.csproj" />
|
||||
<ProjectReference Include="..\Gameboard.ShogiUI.Sockets\Gameboard.ShogiUI.Sockets.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,27 @@
|
||||
using FluentAssertions;
|
||||
using Gameboard.ShogiUI.Sockets.Models;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace Gameboard.ShogiUI.Sockets.UnitTests.Models
|
||||
{
|
||||
[TestClass]
|
||||
public class CoordsModelShould
|
||||
{
|
||||
[TestMethod]
|
||||
public void ConvertToNotation()
|
||||
{
|
||||
var letters = "ABCDEFGHI";
|
||||
|
||||
for (var x = 0; x < 8; x++) // file
|
||||
{
|
||||
for (var y = 0; y < 8; y++) // rank
|
||||
{
|
||||
var move = new Coords(x, y);
|
||||
var actual = move.ToBoardNotation();
|
||||
var expected = $"{letters[x]}{y + 1}";
|
||||
actual.Should().Be(expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gameboard.ShogiUI.Sockets",
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gameboard.ShogiUI.Sockets.ServiceModels", "Gameboard.ShogiUI.Sockets.ServiceModels\Gameboard.ShogiUI.Sockets.ServiceModels.csproj", "{FE775DE4-50F0-4C5D-AD2B-01320B1E7086}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{F35A56FB-B8D8-4CB7-ABF6-D40049C9B42E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gameboard.ShogiUI.Sockets.UnitTests", "Gameboard.ShogiUI.Sockets.UnitTests\Gameboard.ShogiUI.Sockets.UnitTests.csproj", "{8D753AD0-0985-415C-80B3-CCADF3AE1DF9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -21,10 +25,17 @@ Global
|
||||
{FE775DE4-50F0-4C5D-AD2B-01320B1E7086}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FE775DE4-50F0-4C5D-AD2B-01320B1E7086}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FE775DE4-50F0-4C5D-AD2B-01320B1E7086}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8D753AD0-0985-415C-80B3-CCADF3AE1DF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8D753AD0-0985-415C-80B3-CCADF3AE1DF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8D753AD0-0985-415C-80B3-CCADF3AE1DF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8D753AD0-0985-415C-80B3-CCADF3AE1DF9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{8D753AD0-0985-415C-80B3-CCADF3AE1DF9} = {F35A56FB-B8D8-4CB7-ABF6-D40049C9B42E}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {1D0B04F2-0DA1-4CB4-A82A-5A1C3B52ACEB}
|
||||
EndGlobalSection
|
||||
|
||||
6
Gameboard.ShogiUI.Sockets/Managers/BoardManager.cs
Normal file
6
Gameboard.ShogiUI.Sockets/Managers/BoardManager.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Gameboard.ShogiUI.Sockets.Managers
|
||||
{
|
||||
public class BoardManager
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -41,13 +41,11 @@ namespace Gameboard.ShogiUI.Sockets.Managers.ClientActionHandlers
|
||||
}
|
||||
else
|
||||
{
|
||||
var session = new Session(getGameResponse.Session);
|
||||
communicationManager.SubscribeToGame(socket, session, userName);
|
||||
var sessionModel = new Session(getGameResponse.Session);
|
||||
communicationManager.SubscribeToGame(socket, sessionModel, userName);
|
||||
|
||||
response.Game = session.ToServiceModel();
|
||||
response.Moves = userName.Equals(session.Player1)
|
||||
? getMovesResponse.Moves.Select(_ => Mapper.Map(_))
|
||||
: getMovesResponse.Moves.Select(_ => Move.ConvertPerspective(Mapper.Map(_)));
|
||||
response.Game = sessionModel.ToServiceModel();
|
||||
response.Moves = getMovesResponse.Moves.Select(_ => Mapper.Map(_).ToServiceModel());
|
||||
}
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(response);
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
using Gameboard.ShogiUI.Sockets.Extensions;
|
||||
using Gameboard.ShogiUI.Sockets.Managers.Utility;
|
||||
using Gameboard.ShogiUI.Sockets.Repositories;
|
||||
using Gameboard.ShogiUI.Sockets.ServiceModels.Socket.Messages;
|
||||
using Gameboard.ShogiUI.Sockets.ServiceModels.Socket.Types;
|
||||
using Service = Gameboard.ShogiUI.Sockets.ServiceModels.Socket;
|
||||
using Newtonsoft.Json;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading.Tasks;
|
||||
using Gameboard.ShogiUI.Sockets.Models;
|
||||
|
||||
namespace Gameboard.ShogiUI.Sockets.Managers.ClientActionHandlers
|
||||
{
|
||||
@@ -24,12 +24,12 @@ namespace Gameboard.ShogiUI.Sockets.Managers.ClientActionHandlers
|
||||
|
||||
public async Task Handle(WebSocket socket, string json, string userName)
|
||||
{
|
||||
var request = JsonConvert.DeserializeObject<MoveRequest>(json);
|
||||
var request = JsonConvert.DeserializeObject<Service.Messages.MoveRequest>(json);
|
||||
// Basic move validation
|
||||
if (request.Move.To.Equals(request.Move.From))
|
||||
{
|
||||
var serialized = JsonConvert.SerializeObject(
|
||||
new ErrorResponse(ClientAction.Move)
|
||||
new Service.Messages.ErrorResponse(Service.Types.ClientAction.Move)
|
||||
{
|
||||
Error = "Error: moving piece from tile to the same tile."
|
||||
});
|
||||
@@ -37,25 +37,17 @@ namespace Gameboard.ShogiUI.Sockets.Managers.ClientActionHandlers
|
||||
return;
|
||||
}
|
||||
|
||||
var moveModel = new Move(request.Move);
|
||||
var session = (await gameboardRepository.GetGame(request.GameName)).Session;
|
||||
var isPlayer2 = userName == session.Player2;
|
||||
// Shogi.Api expects the move coordinates from the perspective of player 1.
|
||||
var move = isPlayer2 ? Move.ConvertPerspective(request.Move) : request.Move;
|
||||
await gameboardRepository.PostMove(request.GameName, new PostMove(Mapper.Map(move)));
|
||||
await gameboardRepository.PostMove(request.GameName, new PostMove(Mapper.Map(moveModel)));
|
||||
|
||||
var responseForPlayer1 = new MoveResponse(ClientAction.Move)
|
||||
var response = new Service.Messages.MoveResponse(Service.Types.ClientAction.Move)
|
||||
{
|
||||
GameName = request.GameName,
|
||||
PlayerName = userName,
|
||||
Move = isPlayer2 ? Move.ConvertPerspective(request.Move) : request.Move
|
||||
Move = moveModel.ToServiceModel()
|
||||
};
|
||||
var responseForPlayer2 = new MoveResponse(ClientAction.Move)
|
||||
{
|
||||
GameName = request.GameName,
|
||||
PlayerName = userName,
|
||||
Move = isPlayer2 ? request.Move : Move.ConvertPerspective(request.Move)
|
||||
};
|
||||
await communicationManager.BroadcastToGame(session.Name, responseForPlayer1, responseForPlayer2);
|
||||
await communicationManager.BroadcastToGame(session.Name, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Gameboard.ShogiUI.Sockets.ServiceModels.Socket.Types;
|
||||
using Gameboard.ShogiUI.Sockets.Models;
|
||||
using Microsoft.FSharp.Core;
|
||||
using ShogiApi = Gameboard.Shogi.Api.ServiceModels.Types;
|
||||
|
||||
@@ -55,8 +55,8 @@ namespace Gameboard.ShogiUI.Sockets.Managers.Utility
|
||||
|
||||
var target = new Move
|
||||
{
|
||||
From = new Coords { X = origin.X, Y = origin.Y },
|
||||
To = new Coords { X = destination.X, Y = destination.Y },
|
||||
From = new Coords(origin.X, origin.Y),
|
||||
To = new Coords(destination.X, destination.Y),
|
||||
IsPromotion = source.IsPromotion,
|
||||
PieceFromCaptured = pieceFromCaptured
|
||||
};
|
||||
|
||||
41
Gameboard.ShogiUI.Sockets/Models/Coords.cs
Normal file
41
Gameboard.ShogiUI.Sockets/Models/Coords.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Gameboard.ShogiUI.Sockets.Models
|
||||
{
|
||||
public class Coords
|
||||
{
|
||||
private const string BoardNotationRegex = @"(?<file>[A-I])(?<rank>[1-9])";
|
||||
private const char A = 'A';
|
||||
public int X { get; }
|
||||
public int Y { get; }
|
||||
public Coords(int x, int y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
public string ToBoardNotation()
|
||||
{
|
||||
var file = (char)(X + A);
|
||||
var rank = Y + 1;
|
||||
return $"{file}{rank}";
|
||||
}
|
||||
|
||||
public static Coords FromBoardNotation(string notation)
|
||||
{
|
||||
if (string.IsNullOrEmpty(notation))
|
||||
{
|
||||
if (Regex.IsMatch(notation, BoardNotationRegex))
|
||||
{
|
||||
var match = Regex.Match(notation, BoardNotationRegex);
|
||||
char file = match.Groups["file"].Value[0];
|
||||
int rank = int.Parse(match.Groups["rank"].Value);
|
||||
return new Coords(file - A, rank);
|
||||
}
|
||||
throw new ArgumentException("Board notation not recognized."); // TODO: Move this error handling to the service layer.
|
||||
}
|
||||
return new Coords(-1, -1); // Temporarily this is how I tell Gameboard.API that a piece came from the hand.
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Gameboard.ShogiUI.Sockets/Models/Move.cs
Normal file
27
Gameboard.ShogiUI.Sockets/Models/Move.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace Gameboard.ShogiUI.Sockets.Models
|
||||
{
|
||||
public class Move
|
||||
{
|
||||
public string PieceFromCaptured { get; set; }
|
||||
public Coords From { get; set; }
|
||||
public Coords To { get; set; }
|
||||
public bool IsPromotion { get; set; }
|
||||
|
||||
public Move() { }
|
||||
public Move(ServiceModels.Socket.Types.Move move)
|
||||
{
|
||||
From = Coords.FromBoardNotation(move.From);
|
||||
To = Coords.FromBoardNotation(move.To);
|
||||
PieceFromCaptured = move.PieceFromCaptured;
|
||||
IsPromotion = move.IsPromotion;
|
||||
}
|
||||
|
||||
public ServiceModels.Socket.Types.Move ToServiceModel() => new ServiceModels.Socket.Types.Move
|
||||
{
|
||||
From = From.ToBoardNotation(),
|
||||
IsPromotion = IsPromotion,
|
||||
PieceFromCaptured = PieceFromCaptured,
|
||||
To = To.ToBoardNotation()
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user