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
|
namespace Gameboard.ShogiUI.Sockets.ServiceModels.Socket.Types
|
||||||
{
|
{
|
||||||
public class Move
|
public class Move
|
||||||
{
|
{
|
||||||
public string PieceFromCaptured { get; set; }
|
public string PieceFromCaptured { get; set; }
|
||||||
public Coords From { get; set; }
|
/// <summary>Board position notation, like A3 or G1</summary>
|
||||||
public Coords To { get; set; }
|
public string From { get; set; }
|
||||||
public bool IsPromotion { get; set; }
|
/// <summary>Board position notation, like A3 or G1</summary>
|
||||||
|
public string To { get; set; }
|
||||||
/// <summary>
|
public bool IsPromotion { get; set; }
|
||||||
/// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
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}"
|
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
|
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
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
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}.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.ActiveCfg = Release|Any CPU
|
||||||
{FE775DE4-50F0-4C5D-AD2B-01320B1E7086}.Release|Any CPU.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{8D753AD0-0985-415C-80B3-CCADF3AE1DF9} = {F35A56FB-B8D8-4CB7-ABF6-D40049C9B42E}
|
||||||
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {1D0B04F2-0DA1-4CB4-A82A-5A1C3B52ACEB}
|
SolutionGuid = {1D0B04F2-0DA1-4CB4-A82A-5A1C3B52ACEB}
|
||||||
EndGlobalSection
|
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
|
else
|
||||||
{
|
{
|
||||||
var session = new Session(getGameResponse.Session);
|
var sessionModel = new Session(getGameResponse.Session);
|
||||||
communicationManager.SubscribeToGame(socket, session, userName);
|
communicationManager.SubscribeToGame(socket, sessionModel, userName);
|
||||||
|
|
||||||
response.Game = session.ToServiceModel();
|
response.Game = sessionModel.ToServiceModel();
|
||||||
response.Moves = userName.Equals(session.Player1)
|
response.Moves = getMovesResponse.Moves.Select(_ => Mapper.Map(_).ToServiceModel());
|
||||||
? getMovesResponse.Moves.Select(_ => Mapper.Map(_))
|
|
||||||
: getMovesResponse.Moves.Select(_ => Move.ConvertPerspective(Mapper.Map(_)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var serialized = JsonConvert.SerializeObject(response);
|
var serialized = JsonConvert.SerializeObject(response);
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
using Gameboard.ShogiUI.Sockets.Extensions;
|
using Gameboard.ShogiUI.Sockets.Extensions;
|
||||||
using Gameboard.ShogiUI.Sockets.Managers.Utility;
|
using Gameboard.ShogiUI.Sockets.Managers.Utility;
|
||||||
using Gameboard.ShogiUI.Sockets.Repositories;
|
using Gameboard.ShogiUI.Sockets.Repositories;
|
||||||
using Gameboard.ShogiUI.Sockets.ServiceModels.Socket.Messages;
|
using Service = Gameboard.ShogiUI.Sockets.ServiceModels.Socket;
|
||||||
using Gameboard.ShogiUI.Sockets.ServiceModels.Socket.Types;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Gameboard.ShogiUI.Sockets.Models;
|
||||||
|
|
||||||
namespace Gameboard.ShogiUI.Sockets.Managers.ClientActionHandlers
|
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)
|
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
|
// Basic move validation
|
||||||
if (request.Move.To.Equals(request.Move.From))
|
if (request.Move.To.Equals(request.Move.From))
|
||||||
{
|
{
|
||||||
var serialized = JsonConvert.SerializeObject(
|
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."
|
Error = "Error: moving piece from tile to the same tile."
|
||||||
});
|
});
|
||||||
@@ -37,25 +37,17 @@ namespace Gameboard.ShogiUI.Sockets.Managers.ClientActionHandlers
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var moveModel = new Move(request.Move);
|
||||||
var session = (await gameboardRepository.GetGame(request.GameName)).Session;
|
var session = (await gameboardRepository.GetGame(request.GameName)).Session;
|
||||||
var isPlayer2 = userName == session.Player2;
|
await gameboardRepository.PostMove(request.GameName, new PostMove(Mapper.Map(moveModel)));
|
||||||
// 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)));
|
|
||||||
|
|
||||||
var responseForPlayer1 = new MoveResponse(ClientAction.Move)
|
var response = new Service.Messages.MoveResponse(Service.Types.ClientAction.Move)
|
||||||
{
|
{
|
||||||
GameName = request.GameName,
|
GameName = request.GameName,
|
||||||
PlayerName = userName,
|
PlayerName = userName,
|
||||||
Move = isPlayer2 ? Move.ConvertPerspective(request.Move) : request.Move
|
Move = moveModel.ToServiceModel()
|
||||||
};
|
};
|
||||||
var responseForPlayer2 = new MoveResponse(ClientAction.Move)
|
await communicationManager.BroadcastToGame(session.Name, response);
|
||||||
{
|
|
||||||
GameName = request.GameName,
|
|
||||||
PlayerName = userName,
|
|
||||||
Move = isPlayer2 ? request.Move : Move.ConvertPerspective(request.Move)
|
|
||||||
};
|
|
||||||
await communicationManager.BroadcastToGame(session.Name, responseForPlayer1, responseForPlayer2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Gameboard.ShogiUI.Sockets.ServiceModels.Socket.Types;
|
using Gameboard.ShogiUI.Sockets.Models;
|
||||||
using Microsoft.FSharp.Core;
|
using Microsoft.FSharp.Core;
|
||||||
using ShogiApi = Gameboard.Shogi.Api.ServiceModels.Types;
|
using ShogiApi = Gameboard.Shogi.Api.ServiceModels.Types;
|
||||||
|
|
||||||
@@ -55,8 +55,8 @@ namespace Gameboard.ShogiUI.Sockets.Managers.Utility
|
|||||||
|
|
||||||
var target = new Move
|
var target = new Move
|
||||||
{
|
{
|
||||||
From = new Coords { X = origin.X, Y = origin.Y },
|
From = new Coords(origin.X, origin.Y),
|
||||||
To = new Coords { X = destination.X, Y = destination.Y },
|
To = new Coords(destination.X, destination.Y),
|
||||||
IsPromotion = source.IsPromotion,
|
IsPromotion = source.IsPromotion,
|
||||||
PieceFromCaptured = pieceFromCaptured
|
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