a lot of stuff
This commit is contained in:
4
.editorconfig
Normal file
4
.editorconfig
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[*.cs]
|
||||||
|
|
||||||
|
# IDE1006: Naming Styles
|
||||||
|
dotnet_diagnostic.IDE1006.severity = none
|
||||||
@@ -5,6 +5,11 @@ VisualStudioVersion = 17.6.33723.286
|
|||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Squiddler-Server-Lite", "Squiddler-Server-Lite\Squiddler-Server-Lite.csproj", "{89A88EA7-771B-4E74-B662-C13363C4C140}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Squiddler-Server-Lite", "Squiddler-Server-Lite\Squiddler-Server-Lite.csproj", "{89A88EA7-771B-4E74-B662-C13363C4C140}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B32566A0-4B05-4EB6-8BB8-B98E7DA76B25}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
.editorconfig = .editorconfig
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|||||||
101
Squiddler-Server-Lite/Api.cs
Normal file
101
Squiddler-Server-Lite/Api.cs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Squiddler_Server_Lite.StateObjects;
|
||||||
|
using Squiddler_Server_Lite.TransferObjects;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Squiddler_Server_Lite
|
||||||
|
{
|
||||||
|
internal static class Api
|
||||||
|
{
|
||||||
|
internal static async Task<IResult> CreateGame([FromBody] [Required] NewGameConfiguration config)
|
||||||
|
{
|
||||||
|
if (!config.Validate())
|
||||||
|
return TypedResults.BadRequest("Invalid configuration");
|
||||||
|
var gameState = GameState.Create(config);
|
||||||
|
return TypedResults.Ok(gameState.gameCode);
|
||||||
|
}
|
||||||
|
internal static async Task<IResult> DrawCard(HttpContext context)
|
||||||
|
{
|
||||||
|
var gameCode = GetGameCode(context.Request);
|
||||||
|
var playerName = GetPlayerName(context.Request);
|
||||||
|
if (gameCode is null)
|
||||||
|
return TypedResults.BadRequest("No/Invalid game code");
|
||||||
|
if (playerName is null)
|
||||||
|
return TypedResults.BadRequest("No/Invalid player name");
|
||||||
|
return TypedResults.Ok(new Card("A", 2));
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
internal static async Task<IResult> GetTestCard(string text, int value)
|
||||||
|
=> TypedResults.Ok(new Card(text, value));
|
||||||
|
internal static async Task<IResult> JoinGame(HttpContext context)
|
||||||
|
{
|
||||||
|
var gameCode = GetGameCode(context.Request);
|
||||||
|
var playerName = GetPlayerName(context.Request);
|
||||||
|
if (gameCode is null)
|
||||||
|
return TypedResults.BadRequest("No/Invalid game code");
|
||||||
|
if (playerName is null)
|
||||||
|
return TypedResults.BadRequest("No/Invalid player name");
|
||||||
|
var gameState = GameState.FindGame(gameCode);
|
||||||
|
if (gameState is null)
|
||||||
|
return TypedResults.BadRequest("Game code not found");
|
||||||
|
switch (gameState.JoinGame(playerName))
|
||||||
|
{
|
||||||
|
case GameState.JoinGameResult.Success:
|
||||||
|
return TypedResults.Ok();
|
||||||
|
case GameState.JoinGameResult.AlreadyJoined:
|
||||||
|
return TypedResults.Ok();
|
||||||
|
case GameState.JoinGameResult.Full:
|
||||||
|
return TypedResults.Conflict("Game is full");
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal static async Task<IResult> PlayCards(HttpContext context,
|
||||||
|
[FromBody] [Required] PlayedCards played)
|
||||||
|
{
|
||||||
|
var gameCode = GetGameCode(context.Request);
|
||||||
|
var playerName = GetPlayerName(context.Request);
|
||||||
|
if (gameCode is null)
|
||||||
|
return TypedResults.BadRequest("No/Invalid game code");
|
||||||
|
if (playerName is null)
|
||||||
|
return TypedResults.BadRequest("No/Invalid player name");
|
||||||
|
var gameState = GameState.FindGame(gameCode);
|
||||||
|
if (gameState is null)
|
||||||
|
return TypedResults.BadRequest("Game code not found");
|
||||||
|
var player = gameState.ActivePlayer();
|
||||||
|
if (player.userName != playerName)
|
||||||
|
return TypedResults.BadRequest("Not the active player");
|
||||||
|
if (!gameState.playerDrew)
|
||||||
|
{
|
||||||
|
var drawnCard = gameState.PlayerTakesFromDiscard();
|
||||||
|
if (!gameState.ValidatePlayedCards(played))
|
||||||
|
{
|
||||||
|
gameState.PlayerDiscard(drawnCard);
|
||||||
|
return TypedResults.BadRequest("Cards don't match player hand");
|
||||||
|
}
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
private static GameCode? GetGameCode(HttpRequest request)
|
||||||
|
{
|
||||||
|
if (request.Headers.ContainsKey(Headers.GAMECODE))
|
||||||
|
if (GameCode.TryParse(request.Headers[Headers.GAMECODE].ToString(),
|
||||||
|
out GameCode gameCode))
|
||||||
|
return gameCode;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
private static string? GetPlayerName(HttpRequest request)
|
||||||
|
{
|
||||||
|
if (request.Headers.ContainsKey(Headers.PLAYERNAME))
|
||||||
|
return request.Headers[Headers.PLAYERNAME].ToString();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public static class Headers
|
||||||
|
{
|
||||||
|
public const string GAMECODE = "GAME-CODE";
|
||||||
|
public const string PLAYERNAME = "PLAYER-NAME";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
Squiddler-Server-Lite/Middleware/RequireGameCode.cs
Normal file
16
Squiddler-Server-Lite/Middleware/RequireGameCode.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
namespace Squiddler_Server_Lite.Middleware
|
||||||
|
{
|
||||||
|
public class RequireGameCode
|
||||||
|
{
|
||||||
|
private readonly RequestDelegate _next;
|
||||||
|
public RequireGameCode(RequestDelegate next)
|
||||||
|
{
|
||||||
|
_next = next;
|
||||||
|
}
|
||||||
|
public async Task Invoke(HttpContext context)
|
||||||
|
{
|
||||||
|
if (context.Request.Headers.ContainsKey(Api.Headers.GAMECODE))
|
||||||
|
await _next.Invoke(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,24 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Squiddler_Server_Lite;
|
||||||
|
using Squiddler_Server_Lite.Middleware;
|
||||||
|
using Squiddler_Server_Lite.TransferObjects;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen();
|
builder.Services.AddSwaggerGen(options =>
|
||||||
|
{
|
||||||
|
options.SupportNonNullableReferenceTypes();
|
||||||
|
options.MapType<GameCode>(() => new OpenApiSchema
|
||||||
|
{
|
||||||
|
Type = "string",
|
||||||
|
MinLength = 4,
|
||||||
|
MaxLength = 4,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
@@ -15,7 +30,74 @@ if (app.Environment.IsDevelopment())
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
|
app.UseWebSockets();
|
||||||
|
|
||||||
|
var apiPrefix = app.MapGroup("/api");
|
||||||
|
|
||||||
|
apiPrefix.MapGet("/test/card/{text}/{value}", Api.GetTestCard)
|
||||||
|
.Produces<Card>(200, "application/json")
|
||||||
|
.WithName("Test_GetCard")
|
||||||
|
.WithOpenApi();
|
||||||
|
|
||||||
|
apiPrefix.MapPost("/create_game", Api.CreateGame)
|
||||||
|
.Produces<GameCode>(200, "text/plain")
|
||||||
|
.Produces<string>(400, "text/plain")
|
||||||
|
.WithName("CreateNewGame")
|
||||||
|
.WithOpenApi();
|
||||||
|
|
||||||
|
var playPrefix = apiPrefix.MapGroup("/play")
|
||||||
|
.WithOpenApi(op =>
|
||||||
|
{
|
||||||
|
OpenApiOperation newOp = new(op);
|
||||||
|
newOp.Parameters.Add(new OpenApiParameter
|
||||||
|
{
|
||||||
|
Required = true,
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Style = ParameterStyle.Simple,
|
||||||
|
AllowEmptyValue = false,
|
||||||
|
Name = Api.Headers.GAMECODE,
|
||||||
|
Schema = new OpenApiSchema
|
||||||
|
{
|
||||||
|
Type = "string",
|
||||||
|
MaxLength = 4,
|
||||||
|
MinLength = 4
|
||||||
|
},
|
||||||
|
});
|
||||||
|
newOp.Parameters.Add(new OpenApiParameter
|
||||||
|
{
|
||||||
|
Required = true,
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Style = ParameterStyle.Simple,
|
||||||
|
AllowEmptyValue = false,
|
||||||
|
Name = Api.Headers.PLAYERNAME,
|
||||||
|
Schema = new OpenApiSchema { Type = "string" },
|
||||||
|
});
|
||||||
|
return newOp;
|
||||||
|
});
|
||||||
|
|
||||||
|
playPrefix.MapPut("/draw_card", (Delegate)Api.DrawCard)
|
||||||
|
.Produces<Card>(200, "application/json")
|
||||||
|
.Produces<string>(400, "text/plain")
|
||||||
|
.WithName("DrawCard")
|
||||||
|
.WithOpenApi();
|
||||||
|
|
||||||
|
playPrefix.MapPut("/join_game", (Delegate)Api.JoinGame)
|
||||||
|
.Produces(200)
|
||||||
|
.Produces<string>(400, "text/plain")
|
||||||
|
.Produces<string>(409, "text/plain")
|
||||||
|
.WithName("JoinGame")
|
||||||
|
.WithOpenApi();
|
||||||
|
|
||||||
|
playPrefix.MapPut("/play_cards", (Delegate)Api.PlayCards)
|
||||||
|
.Produces(200)
|
||||||
|
.Produces<string>(400, "text/plain")
|
||||||
|
.WithName("PlayCards")
|
||||||
|
.WithOpenApi();
|
||||||
|
|
||||||
|
|
||||||
|
app.Run();
|
||||||
|
|
||||||
|
/*
|
||||||
var summaries = new[]
|
var summaries = new[]
|
||||||
{
|
{
|
||||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||||
@@ -36,9 +118,8 @@ app.MapGet("/weatherforecast", () =>
|
|||||||
.WithName("GetWeatherForecast")
|
.WithName("GetWeatherForecast")
|
||||||
.WithOpenApi();
|
.WithOpenApi();
|
||||||
|
|
||||||
app.Run();
|
|
||||||
|
|
||||||
internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
|
internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
|
||||||
{
|
{
|
||||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
<RootNamespace>Squiddler_Server_Lite</RootNamespace>
|
<RootNamespace>Squiddler_Server_Lite</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.5" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||||
|
|||||||
89
Squiddler-Server-Lite/StateObjects/GameState.cs
Normal file
89
Squiddler-Server-Lite/StateObjects/GameState.cs
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
using Squiddler_Server_Lite.TransferObjects;
|
||||||
|
|
||||||
|
namespace Squiddler_Server_Lite.StateObjects
|
||||||
|
{
|
||||||
|
public class GameState
|
||||||
|
{
|
||||||
|
public GameCode gameCode { get; set; }
|
||||||
|
public string gameName { get; set; }
|
||||||
|
public readonly int FIRST_ROUND;
|
||||||
|
public readonly int LAST_ROUND;
|
||||||
|
public int round { get; set; }
|
||||||
|
public List<UserState> users { get; set; }
|
||||||
|
public int activePlayer { get; set; }
|
||||||
|
public List<Card> discard { get; set; } = new();
|
||||||
|
//index of player who first went out, otherwise -1
|
||||||
|
public int playerWentOut { get; set; } = -1;
|
||||||
|
#region TURNSTATE
|
||||||
|
public bool playerDrew { get; set; }
|
||||||
|
#endregion
|
||||||
|
public void AddToDiscard(Card card)
|
||||||
|
{
|
||||||
|
discard.Add(new Card(card));
|
||||||
|
}
|
||||||
|
public Card PlayerTakesFromDiscard()
|
||||||
|
{
|
||||||
|
Card card = discard[discard.Count - 1];
|
||||||
|
discard.RemoveAt(discard.Count - 1);
|
||||||
|
ActivePlayer().hand.Add(card);
|
||||||
|
return new Card(card);
|
||||||
|
}
|
||||||
|
//matches the PlayedCards against the active player's hand
|
||||||
|
public bool ValidatePlayedCards(PlayedCards playedCards)
|
||||||
|
=> playedCards.AllCards().Order().SequenceEqual(ActivePlayer().hand.Order());
|
||||||
|
public JoinGameResult JoinGame(string playerName)
|
||||||
|
{
|
||||||
|
if (users.Any(u => u.userName == playerName))
|
||||||
|
return JoinGameResult.AlreadyJoined;
|
||||||
|
//kind of an abuse of Any() to have side effects
|
||||||
|
return users.Any(u => u.TryJoin(playerName))
|
||||||
|
? JoinGameResult.Success : JoinGameResult.Full;
|
||||||
|
}
|
||||||
|
public UserState ActivePlayer()
|
||||||
|
{
|
||||||
|
return users[activePlayer];
|
||||||
|
}
|
||||||
|
public bool Started()
|
||||||
|
{
|
||||||
|
return round > 0;
|
||||||
|
}
|
||||||
|
private GameState(int firstRound, int lastRound)
|
||||||
|
{
|
||||||
|
FIRST_ROUND = firstRound;
|
||||||
|
LAST_ROUND = lastRound;
|
||||||
|
}
|
||||||
|
public static GameState Create(NewGameConfiguration config)
|
||||||
|
{
|
||||||
|
GameState gameState = new(config.firstRound, config.lastRound)
|
||||||
|
{
|
||||||
|
gameCode = GameCode.CreateRandom(),
|
||||||
|
gameName = config.gameName,
|
||||||
|
users = Enumerable.Range(0, config.playerCount)
|
||||||
|
.Select(i => new UserState()).ToList(),
|
||||||
|
};
|
||||||
|
ActiveStates.Add(gameState);
|
||||||
|
return gameState;
|
||||||
|
}
|
||||||
|
private static readonly List<GameState> ActiveStates = new();
|
||||||
|
public static GameState? FindGame(GameCode gameCode)
|
||||||
|
{
|
||||||
|
return ActiveStates.FirstOrDefault(g => g.gameCode == gameCode, null);
|
||||||
|
}
|
||||||
|
public static bool DeleteGame(GameCode gameCode)
|
||||||
|
{
|
||||||
|
return ActiveStates.RemoveAll(g => g.gameCode == gameCode) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void PlayerDiscard(Card drawnCard)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum JoinGameResult
|
||||||
|
{
|
||||||
|
Success,
|
||||||
|
Full,
|
||||||
|
AlreadyJoined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
Squiddler-Server-Lite/StateObjects/PlayAreaState.cs
Normal file
17
Squiddler-Server-Lite/StateObjects/PlayAreaState.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using Squiddler_Server_Lite.TransferObjects;
|
||||||
|
|
||||||
|
namespace Squiddler_Server_Lite.StateObjects
|
||||||
|
{
|
||||||
|
public class PlayAreaState
|
||||||
|
{
|
||||||
|
public readonly List<Card>[] rows =
|
||||||
|
{
|
||||||
|
new(), new(), new(), new(), new(),
|
||||||
|
};
|
||||||
|
//calculates sum of values of played cards
|
||||||
|
public int baseScore()
|
||||||
|
{
|
||||||
|
return rows.Sum(r => r.Sum(c => c.value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
Squiddler-Server-Lite/StateObjects/UserState.cs
Normal file
19
Squiddler-Server-Lite/StateObjects/UserState.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using Squiddler_Server_Lite.TransferObjects;
|
||||||
|
|
||||||
|
namespace Squiddler_Server_Lite.StateObjects
|
||||||
|
{
|
||||||
|
public class UserState
|
||||||
|
{
|
||||||
|
public string? userName { get; set; }
|
||||||
|
public List<Card> hand { get; } = new();
|
||||||
|
public bool TryJoin(string userName)
|
||||||
|
{
|
||||||
|
if (this.userName is null)
|
||||||
|
{
|
||||||
|
this.userName = userName;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
Squiddler-Server-Lite/TransferObjects/Card.cs
Normal file
38
Squiddler-Server-Lite/TransferObjects/Card.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
namespace Squiddler_Server_Lite.TransferObjects
|
||||||
|
{
|
||||||
|
public class Card : IComparable<Card>
|
||||||
|
{
|
||||||
|
public string text { get; set; }
|
||||||
|
public int value { get; set; }
|
||||||
|
public override string ToString()
|
||||||
|
=> $"[\"{text}\": {value}";
|
||||||
|
public Card(string text, int value)
|
||||||
|
{
|
||||||
|
this.text = FixCaps(text) ?? throw new ArgumentNullException(nameof(text));
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
public Card(Card card)
|
||||||
|
{
|
||||||
|
text = card.text;
|
||||||
|
value = card.value;
|
||||||
|
}
|
||||||
|
//fixes text so first letter is capitalized and the rest are lower
|
||||||
|
//behavior undefined is text contains characters other than ASCII letters
|
||||||
|
public static string FixCaps(string text)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
|
return text;
|
||||||
|
return text[..1].ToUpper() + text[1..].ToLower();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(Card? other)
|
||||||
|
{
|
||||||
|
if (other is null)
|
||||||
|
return 1;
|
||||||
|
var sCmp = text.CompareTo(other.text);
|
||||||
|
if (sCmp == 0)
|
||||||
|
return value.CompareTo(other.value);
|
||||||
|
return sCmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
71
Squiddler-Server-Lite/TransferObjects/GameCode.cs
Normal file
71
Squiddler-Server-Lite/TransferObjects/GameCode.cs
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.ExceptionServices;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace Squiddler_Server_Lite.TransferObjects
|
||||||
|
{
|
||||||
|
//[KnownType(typeof(GameCode))]
|
||||||
|
public class GameCode
|
||||||
|
{
|
||||||
|
const string ALLOWED_CHARS = "ABCDEFGHIJKLMNPQRSTVWXYZ";
|
||||||
|
public const int LENGTH = 4;
|
||||||
|
[StringLength(LENGTH, MinimumLength = LENGTH)]
|
||||||
|
public string code { get; set; }
|
||||||
|
private GameCode(string code)
|
||||||
|
{
|
||||||
|
this.code = code ?? throw new ArgumentNullException(nameof(code));
|
||||||
|
}
|
||||||
|
public static GameCode CreateRandom()
|
||||||
|
{
|
||||||
|
var stringChars = new char[LENGTH];
|
||||||
|
for (int i = 0; i < stringChars.Length; i++)
|
||||||
|
stringChars[i] = ALLOWED_CHARS[Random.Shared.Next(ALLOWED_CHARS.Length)];
|
||||||
|
return new GameCode(new string(stringChars));
|
||||||
|
}
|
||||||
|
public static bool TryParse(string text, out GameCode gameCode)
|
||||||
|
{
|
||||||
|
gameCode = new GameCode(text);
|
||||||
|
return gameCode.Validate();
|
||||||
|
}
|
||||||
|
public static implicit operator string(GameCode gameCode)
|
||||||
|
=> gameCode.code;
|
||||||
|
public static bool operator ==(GameCode first, GameCode second)
|
||||||
|
=> first.code == second.code;
|
||||||
|
public static bool operator !=(GameCode first, GameCode second)
|
||||||
|
=> !(first == second);
|
||||||
|
public bool Validate()
|
||||||
|
{
|
||||||
|
return code?.All(ALLOWED_CHARS.Contains) ?? false;
|
||||||
|
}
|
||||||
|
public class GameCodeConverter : TypeConverter
|
||||||
|
{
|
||||||
|
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
|
||||||
|
{
|
||||||
|
if (sourceType == typeof(string))
|
||||||
|
return true;
|
||||||
|
return base.CanConvertFrom(context, sourceType);
|
||||||
|
}
|
||||||
|
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
|
||||||
|
{
|
||||||
|
if (value is string v)
|
||||||
|
{
|
||||||
|
var code = new GameCode(v);
|
||||||
|
if (code.Validate())
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
return base.ConvertFrom(context, culture, value);
|
||||||
|
}
|
||||||
|
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
|
||||||
|
{
|
||||||
|
if (destinationType == typeof(string))
|
||||||
|
if (value is GameCode gameCode)
|
||||||
|
return gameCode.code;
|
||||||
|
return base.ConvertTo(context, culture, value, destinationType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Squiddler_Server_Lite.TransferObjects
|
||||||
|
{
|
||||||
|
public class NewGameConfiguration
|
||||||
|
{
|
||||||
|
public const int MIN_PLAYERS = 2;
|
||||||
|
public const int MAX_PLAYERS = 6;
|
||||||
|
public string gameName { get; set; }
|
||||||
|
[Range(MIN_PLAYERS, MAX_PLAYERS)]
|
||||||
|
public int playerCount { get; set; }
|
||||||
|
[DefaultValue(3)]
|
||||||
|
public int firstRound { get; set; }
|
||||||
|
[DefaultValue(10)]
|
||||||
|
public int lastRound { get; set; }
|
||||||
|
public NewGameConfiguration(string gameName, int playerCount,
|
||||||
|
int firstRound = 3, int lastRound = 10)
|
||||||
|
{
|
||||||
|
this.gameName = gameName ?? throw new ArgumentNullException(nameof(gameName));
|
||||||
|
this.playerCount = playerCount;
|
||||||
|
this.firstRound = firstRound;
|
||||||
|
this.lastRound = lastRound;
|
||||||
|
}
|
||||||
|
public bool Validate()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(gameName))
|
||||||
|
return false;
|
||||||
|
if (playerCount > MAX_PLAYERS || playerCount < MIN_PLAYERS)
|
||||||
|
return false;
|
||||||
|
if (lastRound < firstRound)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
Squiddler-Server-Lite/TransferObjects/PlayedCards.cs
Normal file
32
Squiddler-Server-Lite/TransferObjects/PlayedCards.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
namespace Squiddler_Server_Lite.TransferObjects
|
||||||
|
{
|
||||||
|
public class PlayedCards
|
||||||
|
{
|
||||||
|
public List<Card> word1 { get; set; }
|
||||||
|
public List<Card> word2 { get; set; }
|
||||||
|
public List<Card> word3 { get; set; }
|
||||||
|
public List<Card> word4 { get; set; }
|
||||||
|
public List<Card> word5 { get; set; }
|
||||||
|
public List<Card> unplayed { get; set; }
|
||||||
|
public Card discarded { get; set; }
|
||||||
|
public IEnumerable<Card> AllCards()
|
||||||
|
=> word1.Concat(word2).Concat(word3)
|
||||||
|
.Concat(word4).Concat(word5).Append(discarded);
|
||||||
|
public PlayedCards(IEnumerable<Card> word1,
|
||||||
|
IEnumerable<Card> word2,
|
||||||
|
IEnumerable<Card> word3,
|
||||||
|
IEnumerable<Card> word4,
|
||||||
|
IEnumerable<Card> word5,
|
||||||
|
IEnumerable<Card> unplayed,
|
||||||
|
Card discarded)
|
||||||
|
{
|
||||||
|
this.word1 = word1.ToList();
|
||||||
|
this.word2 = word2.ToList();
|
||||||
|
this.word3 = word3.ToList();
|
||||||
|
this.word4 = word4.ToList();
|
||||||
|
this.word5 = word5.ToList();
|
||||||
|
this.unplayed = unplayed.ToList();
|
||||||
|
this.discarded = discarded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user