29 Commits

Author SHA1 Message Date
Renovate Bot
8c426bfad1 Update dependency Microsoft.Extensions.DependencyInjection to 10.0.7
Some checks failed
check main state / build (9.0.x) (push) Has been cancelled
2026-04-26 17:30:51 +00:00
Renovate Bot
457dff2802 Update dependency Microsoft.NET.Test.Sdk to v18
All checks were successful
check main state / build (9.0.x) (push) Successful in 3m45s
2026-02-07 15:26:15 +00:00
Renovate Bot
acd4e3bbf2 Update dependency NUnit3TestAdapter to v6
All checks were successful
check main state / build (9.0.x) (push) Successful in 2m6s
2026-02-07 14:33:42 +00:00
Renovate Bot
a4c85cd482 Update actions/checkout action to v6
All checks were successful
check main state / build (9.0.x) (push) Successful in 2m6s
2026-02-06 22:38:09 +00:00
Renovate Bot
483b92b830 Update dependency Microsoft.Extensions.DependencyInjection to v10
All checks were successful
check main state / build (9.0.x) (push) Successful in 2m8s
2026-02-06 22:20:11 +00:00
Renovate Bot
2394c325a3 Update actions/setup-dotnet action to v5
All checks were successful
check main state / build (9.0.x) (push) Successful in 2m6s
2026-02-05 21:01:28 +00:00
Renovate Bot
5cebb9a800 Update dependency NUnit3TestAdapter to 5.2.0
All checks were successful
check main state / build (9.0.x) (push) Successful in 2m31s
2026-02-05 18:28:38 +00:00
Renovate Bot
3d11413e6b Update dependency xunit.runner.visualstudio to 3.1.5
All checks were successful
check main state / build (9.0.x) (push) Successful in 2m21s
2026-02-05 16:52:11 +00:00
Renovate Bot
503d8e60c3 Update dependency nunit to 4.4.0
All checks were successful
check main state / build (9.0.x) (push) Successful in 2m56s
2026-02-05 15:43:29 +00:00
Renovate Bot
425e97c912 Update dependency Microsoft.NET.Test.Sdk to 17.14.1
All checks were successful
check main state / build (9.0.x) (push) Successful in 2m24s
2026-02-05 15:34:34 +00:00
Renovate Bot
1348b78420 Update dependency coverlet.collector to 6.0.4
All checks were successful
check main state / build (9.0.x) (push) Successful in 2m26s
2026-02-05 14:34:19 +00:00
Renovate Bot
3206c99073 Update dependency Microsoft.Extensions.DependencyInjection to 9.0.12
All checks were successful
check main state / build (9.0.x) (push) Successful in 2m30s
2026-02-05 14:13:22 +00:00
3dba66344d fin de l'initialisation d'un match et ajout du random aux commandes
All checks were successful
check main state / build (9.0.x) (push) Successful in 2m46s
2025-04-24 22:31:19 +02:00
c1c5f6bab8 ajout des chef et shaman a la creation du match
All checks were successful
check main state / build (9.0.x) (push) Successful in 1m23s
2025-04-24 09:20:26 +02:00
90c93df9c9 ajout des marker et des socles aux joueurs au debut de la partie
All checks were successful
check main state / build (9.0.x) (push) Successful in 1m26s
2025-04-23 16:38:26 +02:00
Renovate Bot
e83dd938e4 Update dependency Microsoft.Extensions.DependencyInjection to v9.0.4
All checks were successful
check main state / build (9.0.x) (push) Successful in 1m27s
2025-04-23 11:52:14 +02:00
1fbce5a4fd augmentation des niveaux de warning dans la solution
Some checks failed
check main state / build (9.0.x) (push) Has been cancelled
2025-04-23 10:44:20 +02:00
a1a1d94a14 Ajout de la base de PrepareMatchCommand avec un test
All checks were successful
check main state / build (9.0.x) (push) Successful in 1m26s
2025-04-17 11:06:21 +02:00
80b3d71104 Mise en place des MatchCommand
All checks were successful
check main state / build (9.0.x) (push) Successful in 1m28s
Ajout des données dynamiques au match
2025-04-03 00:15:11 +02:00
Renovate Bot
4a4446ea48 Update dependency NUnit3TestAdapter to v5
All checks were successful
check main state / build (9.0.x) (push) Successful in 1m22s
2025-04-02 14:29:36 +00:00
Renovate Bot
10dc874d43 Update dependency Microsoft.NET.Test.Sdk to v17
All checks were successful
check main state / build (9.0.x) (push) Successful in 1m25s
2025-04-02 14:04:28 +00:00
Renovate Bot
a558bd16ea Update dependency NUnit3TestAdapter to v3.17.0
All checks were successful
check main state / build (9.0.x) (push) Successful in 1m21s
2025-04-02 13:53:44 +00:00
Renovate Bot
0ebca20478 Update vstest monorepo
All checks were successful
check main state / build (9.0.x) (push) Successful in 1m28s
2025-04-02 15:42:39 +02:00
Renovate Bot
a24e9c9470 Update dependency nunit to v4
Some checks failed
check main state / build (9.0.x) (push) Has been cancelled
2025-04-02 15:41:29 +02:00
Renovate Bot
334f3a45b1 Update dependency xunit.runner.visualstudio to v3
Some checks failed
check main state / build (9.0.x) (push) Has been cancelled
2025-03-31 00:00:33 +00:00
5559fd6368 ajout de la surveillance par renovate
All checks were successful
check main state / build (9.0.x) (push) Successful in 1m34s
2025-03-27 15:37:42 +01:00
af5337b2f2 ajout d'un debut de CI
All checks were successful
check main state / build (9.0.x) (push) Successful in 1m22s
2025-03-26 22:56:43 +01:00
899b1771d0 ajout du boardlayout et de la commande getmatch 2025-03-26 22:21:07 +01:00
7b00a91580 ajout de la commande de creation de match 2025-03-12 23:33:10 +01:00
36 changed files with 1242 additions and 46 deletions

View File

@@ -5,6 +5,8 @@ root = true
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
charset = utf-8 charset = utf-8
dotnet_diagnostic.CA1307.severity = none
dotnet_diagnostic.CA5394.severity = none //Pour l'utilisation de random
[Src/HexagonalLib/**] [Src/HexagonalLib/**]
generated_code = true generated_code = true

View File

@@ -0,0 +1,26 @@
name: check main state
on: [push]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
dotnet-version: [ '9.0.x' ]
steps:
- uses: actions/checkout@v6
- name: Setup dotnet
uses: actions/setup-dotnet@v5
with:
dotnet-version: '9.0.x'
- name: Install dependencies
run: dotnet restore ./Giants.sln
- name: Build
run: dotnet build ./Giants.sln
- name: Check format
run: dotnet format
- name: Test with the dotnet CLI
run: dotnet test ./Giants.sln

View File

@@ -15,6 +15,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Giants.Infrastructure", "Sr
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Giants.Application", "Src\Giants.Application\Giants.Application.csproj", "{1EF04517-2D31-4130-A687-7954A5431312}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Giants.Application", "Src\Giants.Application\Giants.Application.csproj", "{1EF04517-2D31-4130-A687-7954A5431312}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Giants.Application.Tests", "Tests\Giants.Application.Tests\Giants.Application.Tests.csproj", "{7A23A70F-68C9-4463-A980-E7597A621FDD}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -40,11 +42,16 @@ Global
{1EF04517-2D31-4130-A687-7954A5431312}.Debug|Any CPU.Build.0 = Debug|Any CPU {1EF04517-2D31-4130-A687-7954A5431312}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1EF04517-2D31-4130-A687-7954A5431312}.Release|Any CPU.ActiveCfg = Release|Any CPU {1EF04517-2D31-4130-A687-7954A5431312}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1EF04517-2D31-4130-A687-7954A5431312}.Release|Any CPU.Build.0 = Release|Any CPU {1EF04517-2D31-4130-A687-7954A5431312}.Release|Any CPU.Build.0 = Release|Any CPU
{7A23A70F-68C9-4463-A980-E7597A621FDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7A23A70F-68C9-4463-A980-E7597A621FDD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7A23A70F-68C9-4463-A980-E7597A621FDD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7A23A70F-68C9-4463-A980-E7597A621FDD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{A7B8B752-2AE9-4FB2-8F51-733F96C4CFD0} = {824D17BD-3CFE-498A-967D-3F42DF5EE92D} {A7B8B752-2AE9-4FB2-8F51-733F96C4CFD0} = {824D17BD-3CFE-498A-967D-3F42DF5EE92D}
{30032CBC-0B7B-4BF3-9682-C506460F0FE6} = {F34871C1-07BB-4012-A310-3FFDD6DC7DBA} {30032CBC-0B7B-4BF3-9682-C506460F0FE6} = {F34871C1-07BB-4012-A310-3FFDD6DC7DBA}
{E6B2C76F-9CE2-4ADA-97F9-CEE24D48B65F} = {824D17BD-3CFE-498A-967D-3F42DF5EE92D} {E6B2C76F-9CE2-4ADA-97F9-CEE24D48B65F} = {824D17BD-3CFE-498A-967D-3F42DF5EE92D}
{1EF04517-2D31-4130-A687-7954A5431312} = {824D17BD-3CFE-498A-967D-3F42DF5EE92D} {1EF04517-2D31-4130-A687-7954A5431312} = {824D17BD-3CFE-498A-967D-3F42DF5EE92D}
{7A23A70F-68C9-4463-A980-E7597A621FDD} = {F34871C1-07BB-4012-A310-3FFDD6DC7DBA}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

BIN
Graphics/plan.pdn Normal file

Binary file not shown.

View File

@@ -9,17 +9,17 @@ namespace Giants.Application;
/// </summary> /// </summary>
public class MatchRepositoryMock : IMatchRepository public class MatchRepositoryMock : IMatchRepository
{ {
private readonly IHexagonalGrid _gridLayout; private readonly BoardLayout _boardLayout;
private static int _lastId = 1; private int _lastId = 1;
private Dictionary<int, Match> _matchs = new Dictionary<int, Match>(); private Dictionary<int, Match> _matchs = new Dictionary<int, Match>();
/// <summary> /// <summary>
/// constructeur /// constructeur
/// </summary> /// </summary>
public MatchRepositoryMock() public MatchRepositoryMock(BoardLayout boardLayout)
{ {
_gridLayout = new HexagonalGridImpl(); _boardLayout = boardLayout;
} }
/// <inheritdoc/> /// <inheritdoc/>
@@ -35,9 +35,10 @@ public class MatchRepositoryMock : IMatchRepository
/// <inheritdoc/> /// <inheritdoc/>
public Match CreateMatch() public Match CreateMatch()
{ {
Match result = new Match(_gridLayout) Match result = new Match()
{ {
Id = _lastId++ Id = _lastId++,
Board = _boardLayout,
}; };
AddStaticData(result); AddStaticData(result);
@@ -52,4 +53,8 @@ public class MatchRepositoryMock : IMatchRepository
} }
public void SetMapData(IHexagonalGrid grid)
{
throw new NotImplementedException();
}
} }

View File

@@ -4,6 +4,10 @@
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<AnalysisMode>All</AnalysisMode>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@@ -8,6 +8,9 @@ public abstract class BaseCommand<T> where T : BaseCommandResult
{ {
protected abstract T LocalExecute(); protected abstract T LocalExecute();
public required Random Random { get; init; }
/// <summary> Executer la commande, si nécessaire il faut avoir rempli les parametres en amont </summary> /// <summary> Executer la commande, si nécessaire il faut avoir rempli les parametres en amont </summary>
public T Execute() public T Execute()
{ {

View File

@@ -7,5 +7,5 @@ namespace Giants.Core.Commands;
public abstract class BaseCommandResult public abstract class BaseCommandResult
{ {
/// <summary> indique si le resultat est un success (true) ou un echec(false) </summary> /// <summary> indique si le resultat est un success (true) ou un echec(false) </summary>
public bool Success { get; init; } = false; public bool Success { get; init; }
} }

View File

@@ -0,0 +1,13 @@
namespace Giants.Core.Commands;
public abstract class BaseMatchCommand<T> : BaseCommand<T> where T : BaseCommandResult
{
public required Match InputMatch { get; init; }
protected abstract T LocalMatchExecute(Match match);
protected override T LocalExecute()
{
return LocalMatchExecute(InputMatch.Clone());
}
}

View File

@@ -0,0 +1,43 @@
using Giants.Core.Interfaces;
namespace Giants.Core.Commands;
/// <summary>
/// Logique metier qui permet d'ajouter les données statiques aux matchs qui arrivent du repository
/// </summary>
public class GetMatchCommand : BaseCommand<GetMatchResult>
{
private IMatchRepository _repo;
/// <summary> L'id du match a récupérer </summary>
public required int MatchId { get; init; }
public GetMatchCommand(IMatchRepository repo)
{
_repo = repo;
}
protected override GetMatchResult LocalExecute()
{
Match? m = _repo.GetMatch(MatchId);
if (null != m)
{
GetMatchResult result = new GetMatchResult()
{
Success = true,
Match = m
};
return result;
}
return new GetMatchResult() { };
}
}
public class GetMatchResult : BaseCommandResult
{
/// <summary> Le match si success null sinon </summary>
public Match? Match { get; init; }
}

View File

@@ -0,0 +1,110 @@
using Giants.Core.Enums;
using Giants.Core.Exceptions;
namespace Giants.Core.Commands;
public class PrepareMatchCommand : BaseMatchCommand<PrepareMatchResult>
{
public required IList<int> PlayerIDs { get; init; }
protected override PrepareMatchResult LocalMatchExecute(Match match)
{
if (PlayerIDs.Count < 3 || PlayerIDs.Count > 5 || null == match)
return new PrepareMatchResult();
//Gestion des assets des joueurs
for (int itePlayer = 0; itePlayer < PlayerIDs.Count; itePlayer++)
{
match.SetPlayer(itePlayer, PlayerIDs[itePlayer]);
Player? player = match.GetPlayer(itePlayer);
if (null == player)
throw new ArgumentException($"Cannot get player {itePlayer} in PrepareMatchCommand");
//socles
int nbSocle = NbSoclePerPlayer(PlayerIDs.Count);
foreach (var socle in player.Bases)
{
if (nbSocle > 0)
{
player.PutPieceInHiddenArea(socle);
nbSocle--;
}
else
{
break;
}
}
//marqueurs tribaux (on ajoute 2 par joueurs et le reste dans l'urne)
int i = 0;
foreach (var marker in player.Markers)
{
if (i < 2)
{
player.PutPieceInHiddenArea(marker);
}
else
{
match.AssignPiece(marker, PiecePosition.Urne);
}
i++;
}
//assigner les ouvriers (1 chef, 1 shaman et 1 worker chacun)
match.AssignPiece(player.Chef, player.HiddenPosition);
match.AssignPiece(player.Shaman, player.HiddenPosition);
int nbWorker = 1;
foreach (PieceIndex worker in player.Workers)
{
if (nbWorker > 0)
{
match.AssignPiece(worker, player.HiddenPosition);
nbWorker--;
}
else
{
match.AssignPiece(worker, PiecePosition.Urne);
}
}
match.AssignPiece(player.Workers.First(), player.HiddenPosition);
//score a zero
for (int iteScore = 0; iteScore < match.NbPlayer; iteScore++)
{
match.SetScore(iteScore, 0);
}
//choix d'un 1er joueur
Player? firstPlayer = match.GetPlayer(Random.Next(match.NbPlayer));
if (null == firstPlayer)
throw new InitialisationException("Cannot select first player, indexOutOfRange");
match.AssignPiece(PieceIndex.StartPlayer, firstPlayer.VisiblePosition);
}
return new PrepareMatchResult()
{
Success = true,
Match = match
};
}
private static int NbSoclePerPlayer(int nbTotalPlayer)
{
return nbTotalPlayer switch
{
3 => 7,
4 => 6,
5 => 5,
_ => throw new DataConversionException("Wrong player count for NbMarkerPerPlayer")
};
}
}
public class PrepareMatchResult : BaseCommandResult
{
public Match? Match { get; init; }
}

View File

@@ -1,5 +1,6 @@
using System.Security.Cryptography.X509Certificates; using System.Collections;
using Giants.Core.Interfaces; using System.Reflection.Metadata.Ecma335;
using Giants.Core.Enums;
namespace Giants.Core; namespace Giants.Core;
@@ -11,18 +12,108 @@ namespace Giants.Core;
public class Match public class Match
{ {
#region données statiques #region données statiques
public int Id { get; init; } public int Id { get; init; }
IHexagonalGrid _grid; public required BoardLayout Board { get; init; }
#endregion #endregion
#region données dynamiques #region données dynamiques
/// <summary>
/// IDs des joueurs qui participent a cette partie,
// -2 Pour une place non ouverte
// -1 pour une place non occupée mais ouverte
/// </summary>
int[] players = [-1, -1, -1, -1, -1];
/// <summary> Les scores des joueurs </summary>
int[] scores = [-1, -1, -1, -1, -1];
/// <summary>
/// etat des dés, -1 indique non utilisé et positif donne le numero de la face,
/// les 3 premiers dés sont les blanc et les 2 suivant les marrons
/// 4e dé utile pour la partie a 4 joueur, le 5e pour les parties a 5 joueurs
/// </summary>
int[] dices = [0, 0, 0, 0, 0,];
/// <summary>
/// Indique si pour une foret donnée le bois a ete ramassé, l'index et les quantités sont dans le boardLayout
/// </summary>
bool[] forestUsed = [false, false, false, false, false, false, false];
/// <summary>
/// un tableau indiquant ou sont placé les pieces, l'index est l'id de la piece et la valeur la position de la piece ///
/// </summary>
PiecePosition[] pieces = new PiecePosition[(int)Enum.GetValues(typeof(PieceIndex)).Cast<PieceIndex>().Max() + 1];
#endregion #endregion
/// <summary> Construction de base </summary> #region Getters
/// <param name="grid"> La grid du jeu</param> public static int MaxTribalMarker { get => 6; }
public Match(IHexagonalGrid grid) public static int MaxSocle { get => 7; }
public int NbPlayer { get => players.Count(p => p != -1); }
public Player? GetPlayer(int index)
{ {
_grid = grid; if (index >= 0 && index < players.Length && players[index] != -1)
return new Player(this)
{
Index = index,
};
return null;
}
#endregion
#region Setters for commands
public void AssignPiece(PieceIndex piece, PiecePosition position)
{
pieces[(int)piece] = position;
}
public void SetPlayer(int index, int playerId)
{
players[index] = playerId;
}
public void SetScore(int index, int score)
{
scores[index] = score;
}
public int GetScore(int index)
{
return scores[index];
}
public PiecePosition GetPiece(PieceIndex PieceIndex)
{
return pieces[(int)PieceIndex];
}
#endregion
/// <summary>
/// Cloner ce match pour pouvoir le modifier
/// </summary>
/// <returns></returns>
public Match Clone()
{
Match result = new Match()
{
Board = Board,
Id = Id,
};
Buffer.BlockCopy(players, 0, result.players, 0, players.Length * sizeof(int));
Buffer.BlockCopy(scores, 0, result.scores, 0, scores.Length * sizeof(int));
Buffer.BlockCopy(dices, 0, result.dices, 0, dices.Length * sizeof(int));
Buffer.BlockCopy(pieces, 0, result.pieces, 0, pieces.Length * sizeof(PieceIndex));
Buffer.BlockCopy(forestUsed, 0, result.forestUsed, 0, forestUsed.Length * sizeof(bool));
return result;
} }
/// <summary> Permet de comparer des Match, cette methode est critique pour l'ia pour reduire son parcour d'arbre </summary> /// <summary> Permet de comparer des Match, cette methode est critique pour l'ia pour reduire son parcour d'arbre </summary>
@@ -30,7 +121,15 @@ public class Match
/// <returns></returns> <summary> /// <returns></returns> <summary>
public override bool Equals(object? obj) public override bool Equals(object? obj)
{ {
return base.Equals(obj); if (obj is Match match)
{
return Enumerable.SequenceEqual(players, match.players) &&
Enumerable.SequenceEqual(scores, match.scores) &&
Enumerable.SequenceEqual(dices, match.dices) &&
Enumerable.SequenceEqual(pieces, match.pieces) &&
Enumerable.SequenceEqual(forestUsed, match.forestUsed);
}
return false;
} }
/// <inheritdoc/> /// <inheritdoc/>

View File

@@ -0,0 +1,74 @@
using System.Collections.ObjectModel;
using System.Reflection.Metadata.Ecma335;
using Giants.Core.Enums;
namespace Giants.Core;
/// <summary>
/// Structure pour agréger les getters liés aux informations d'un joueur
/// </summary>
public class Player
{
private Match _match;
public required int Index { get; init; }
static Player()
{
// preparation des données statiques
return;
}
public Player(Match match)
{
_match = match;
}
#region Collections
public static readonly ICollection<PieceIndex>[] PlayerPieces ={
[.. Enum.GetValues<PieceIndex>().Where(p => p.ToString().Contains("player1"))],
[.. Enum.GetValues<PieceIndex>().Where(p => p.ToString().Contains("player2"))],
[.. Enum.GetValues<PieceIndex>().Where(p => p.ToString().Contains("player3"))],
[.. Enum.GetValues<PieceIndex>().Where(p => p.ToString().Contains("player4"))],
[.. Enum.GetValues<PieceIndex>().Where(p => p.ToString().Contains("player5"))]
};
public static readonly PiecePosition[] PlayerVisibileAreas = { PiecePosition.player1Visible, PiecePosition.player2Visible, PiecePosition.player3Visible, PiecePosition.player4Visible, PiecePosition.player5Visible };
public static readonly PiecePosition[] PlayerHiddenAreas = { PiecePosition.player1Hidden, PiecePosition.player2Hidden, PiecePosition.player3Hidden, PiecePosition.player4Hidden, PiecePosition.player5Hidden };
#endregion Collections
#region Generics
public PiecePosition HiddenPosition => PlayerHiddenAreas[Index];
public PiecePosition VisiblePosition => PlayerVisibileAreas[Index];
public void PutPieceInVisibleArea(PieceIndex piece)
{
_match.AssignPiece(piece, VisiblePosition);
}
public void PutPieceInHiddenArea(PieceIndex piece)
{
_match.AssignPiece(piece, HiddenPosition);
}
public int Score => _match.GetScore(Index);
#endregion
#region workers
public PieceIndex Chef => PlayerPieces[Index].Where(p => p.ToString().Contains("Chief")).FirstOrDefault();
public PieceIndex Shaman => PlayerPieces[Index].Where(p => p.ToString().Contains("Shaman")).FirstOrDefault();
public ICollection<PieceIndex> Workers => [.. PlayerPieces[Index].Where(p => p.ToString().Contains("Worker"))];
#endregion
#region socles
public ICollection<PieceIndex> Bases => PlayerPieces[Index]?.Where(p => p.ToString().Contains("Base")).ToList() ?? [];
public int NbVisibleBase => Bases.Count(p => _match.GetPiece(p) == VisiblePosition);
public int NbHiddenBase => Bases.Count(p => _match.GetPiece(p) == HiddenPosition);
#endregion
#region Tribal markers
public ICollection<PieceIndex> Markers => PlayerPieces[Index]?.Where(p => p.ToString().Contains("TribalMarker")).ToList() ?? [];
public int NbVisibleTribalTokenCount => Markers.Count(p => _match.GetPiece(p) == VisiblePosition);
public int NbHiddenTribalTokenCount => Markers.Count(p => _match.GetPiece(p) == HiddenPosition);
public int NbUrnTribalTokenCount => Markers.Count(p => _match.GetPiece(p) == PiecePosition.Urne);
#endregion
}

View File

@@ -0,0 +1,112 @@
namespace Giants.Core.Enums;
public enum PieceIndex
{
Unknown,
StartPlayer,
player1Chief,
player1Shaman,
player1Worker1,
player1Worker2,
player1Worker3,
player1Worker4,
player1Worker5,
player1Worker6,
player1Base1,
player1Base2,
player1Base3,
player1Base4,
player1Base5,
player1Base6,
player1Base7,
player1TribalMarker1,
player1TribalMarker2,
player1TribalMarker3,
player1TribalMarker4,
player1TribalMarker5,
player1TribalMarker6,
player2Chief,
player2Shaman,
player2Worker1,
player2Worker2,
player2Worker3,
player2Worker4,
player2Worker5,
player2Worker6,
player2Base1,
player2Base2,
player2Base3,
player2Base4,
player2Base5,
player2Base6,
player2Base7,
player2TribalMarker1,
player2TribalMarker2,
player2TribalMarker3,
player2TribalMarker4,
player2TribalMarker5,
player2TribalMarker6,
player3Chief,
player3Shaman,
player3Worker1,
player3Worker2,
player3Worker3,
player3Worker4,
player3Worker5,
player3Worker6,
player3Base1,
player3Base2,
player3Base3,
player3Base4,
player3Base5,
player3Base6,
player3Base7,
player3TribalMarker1,
player3TribalMarker2,
player3TribalMarker3,
player3TribalMarker4,
player3TribalMarker5,
player3TribalMarker6,
player4Chief,
player4Shaman,
player4Worker1,
player4Worker2,
player4Worker3,
player4Worker4,
player4Worker5,
player4Worker6,
player4Base1,
player4Base2,
player4Base3,
player4Base4,
player4Base5,
player4Base6,
player4Base7,
player4TribalMarker1,
player4TribalMarker2,
player4TribalMarker3,
player4TribalMarker4,
player4TribalMarker5,
player4TribalMarker6,
player5Chief,
player5Shaman,
player5Worker1,
player5Worker2,
player5Worker3,
player5Worker4,
player5Worker5,
player5Worker6,
player5Base1,
player5Base2,
player5Base3,
player5Base4,
player5Base5,
player5Base6,
player5Base7,
player5TribalMarker1,
player5TribalMarker2,
player5TribalMarker3,
player5TribalMarker4,
player5TribalMarker5,
player5TribalMarker6
}

View File

@@ -0,0 +1,98 @@
using System.Xml.XPath;
namespace Giants.Core.Enums;
/// <summary>
/// Position que peut prendre une piece dans le jeu
/// </summary>
public enum PiecePosition
{
boite,
player1Visible,
player2Visible,
player3Visible,
player4Visible,
player5Visible,
player1Hidden,
player2Hidden,
player3Hidden,
player4Hidden,
player5Hidden,
Carry,
Urne,
tile22,
tile39,
tile38,
tile37,
tile36,
tile54,
tile53,
tile52,
tile51,
tile50,
tile49,
tile70,
tile69,
tile68,
tile67,
tile66,
tile65,
tile64,
tile84,
tile83,
tile82,
tile81,
tile80,
tile79,
tile100,
tile99,
tile98,
tile97,
tile96,
tile95,
tile115,
tile114,
tile113,
tile112,
tile111,
tile130,
tile129,
tile128,
tile127,
tile145,
tile144,
tile143,
tile161,
tile160,
tile159,
tile177,
tile176,
tile175,
tile192,
tile191,
tile208,
tile207,
tile206,
tile223,
tile222
}
public static class PiecePositionExtension
{
public static PiecePosition FromTileIndex(this BoardLayout piece, int index)
{
string tmp = $"tile{index}";
object? result;
if (Enum.TryParse(typeof(PiecePosition), tmp, out result))
{
if (null != result)
{
return (PiecePosition)result;
}
}
throw new InvalidCastException($"Cannot cast tile index {index}");
}
}

View File

@@ -0,0 +1,14 @@
namespace Giants.Core.Exceptions;
/// <summary>
/// Exception levée lors d'un probleme de conversion d'un objet du core
/// </summary>
public class DataConversionException : System.Exception
{
/// <inheritdoc/>>
public DataConversionException() { }
/// <inheritdoc/>>
public DataConversionException(string message) : base(message) { }
/// <inheritdoc/>>
public DataConversionException(string message, System.Exception inner) : base(message, inner) { }
}

View File

@@ -0,0 +1,14 @@
namespace Giants.Core.Exceptions;
/// <summary>
/// Exception levée lors d'un probleme pendant l'initialisation de la partie
/// </summary>
public class InitialisationException : System.Exception
{
/// <inheritdoc/>>
public InitialisationException() { }
/// <inheritdoc/>>
public InitialisationException(string message) : base(message) { }
/// <inheritdoc/>>
public InitialisationException(string message, System.Exception inner) : base(message, inner) { }
}

View File

@@ -5,5 +5,32 @@ namespace Giants.Core.Interfaces;
/// </summary> /// </summary>
public interface IHexagonalGrid public interface IHexagonalGrid
{ {
/// <summary>
/// indique le style de grille, voir https://www.redblobgames.com/grids/hexagons/ pour des détails
/// </summary>
public enum HexStyle
{
/// <summary> Pointe vers le haut, impaire a droite </summary>
PointyOdd,
/// <summary> Pointe vers le haut, pair a droite </summary>
PointyEven,
/// <summary> Pointe vers le coté, impaire en bas</summary>
FlatOdd,
/// <summary> Pointe vers le coté, impaire en haut</summary>
FlatEven
}
/// <summary>
/// Demande a la grille d'allouer sa taille et son type
/// </summary>
/// <param name="style">le style de grid</param>
public void Init(HexStyle style = HexStyle.PointyOdd);
/// <summary>
/// Permet de recupérer la liste des tiles voisines d'une tile fournie en parametre
/// </summary>
/// <param name="coords">La tuile de laquelle on cherche les voisins</param>
/// <returns>la liste des tiles voisines</returns>
public ICollection<AxialCoords> GetNeighbours(AxialCoords coords);
} }

View File

@@ -1,7 +1,7 @@
namespace Giants.Core.Interfaces; namespace Giants.Core.Interfaces;
/// <summary> /// <summary>
/// Interface de tout fournisseur de match, ils sont responsable d'instancier les match a partir d'un ID ou d'en créer des nouveaux /// Interface de tout fournisseur de match, ils récupere les données dynamiques d'un match
/// </summary> /// </summary>
public interface IMatchRepository public interface IMatchRepository
{ {
@@ -17,4 +17,9 @@ public interface IMatchRepository
/// </summary> /// </summary>
/// <returns>le nouveau match a son état initial</returns> /// <returns>le nouveau match a son état initial</returns>
Match? CreateMatch(); Match? CreateMatch();
/// <summary>
/// Fournir au repository la map a assigner aux match instanciés
/// </summary>
public void SetMapData(IHexagonalGrid grid);
} }

View File

@@ -0,0 +1,19 @@
namespace Giants.Core;
public record struct AxialCoords
{
public int Q { get; init; }
public int R { get; init; }
public AxialCoords(int Q, int R)
{
this.Q = Q;
this.R = R;
}
public AxialCoords()
{
Q = 0;
R = 0;
}
}

View File

@@ -1,9 +1,136 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions;
using Giants.Core.Interfaces;
namespace Giants.Core; namespace Giants.Core;
/// <summary> /// <summary>
/// Represente l'organisation d'un plateau, il ne contient aucune informations liées a une partie mais il permet /// Represente l'organisation d'un plateau, il ne contient aucune informations liées a une partie mais il permet
/// d'effectuer des recherches de chemins ou de type de tuiles /// d'effectuer des recherches de chemins ou de type de tuiles
/// noter que cette classe doit être immuable comme c'est un valueObjet, donc pas des setter autre que init
/// </summary> /// </summary>
public class BoardLayout public class BoardLayout
{ {
IHexagonalGrid _grid;
Dictionary<int, TileInfos> _tiles;
Dictionary<AxialCoords, int> _forest = new Dictionary<AxialCoords, int>(){
{new AxialCoords(4,2),0},
{new AxialCoords(4,1),1},
{new AxialCoords(5,0),2},
{new AxialCoords(5,1),3},
{new AxialCoords(5,2),4},
{new AxialCoords(6,0),5},
{new AxialCoords(6,1),6},
};
int[] _forestQte = [5, 5, 4, 4, 3, 3, 3];
int width = 16;
public BoardLayout(IHexagonalGrid gridSystem)
{
_grid = gridSystem;
BuildDefaultBoard();
}
public ICollection<AxialCoords> GetNeighbours(AxialCoords coords)
{
var tmp = _grid.GetNeighbours(coords);
return tmp.Where(t => _tiles.ContainsKey(Index(t.Q, t.R))).ToList();
}
public int ForestQte(AxialCoords coords)
{
int index = _forest[coords];
return ForestQte(index);
}
public int ForestIndex(AxialCoords coords)
{
if (_forest.TryGetValue(coords, out int value))
{
return value;
}
return -1;
}
public int ForestQte(int index) => _forestQte[index];
[MemberNotNull(nameof(_tiles))]
private void BuildDefaultBoard()
{
_grid.Init(IHexagonalGrid.HexStyle.FlatOdd);
//creation des tiles depuis la position bas gauche vers le haut puis la droite
_tiles = new Dictionary<int, TileInfos>();
AddTile(new TileInfos() { Q = 1, R = 6, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(-1, 0) } });
AddTile(new TileInfos() { Q = 2, R = 7, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(0, 1) } });
AddTile(new TileInfos() { Q = 2, R = 6, TileType = TileTypes.Village });
AddTile(new TileInfos() { Q = 2, R = 5, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(-1, 0) } });
AddTile(new TileInfos() { Q = 2, R = 4, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(-1, 0) } });
AddTile(new TileInfos() { Q = 3, R = 6, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(0, 1) } });
AddTile(new TileInfos() { Q = 3, R = 5, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 3, R = 4, TileType = TileTypes.HatCarry });
AddTile(new TileInfos() { Q = 3, R = 3, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(-1, 0) } });
AddTile(new TileInfos() { Q = 3, R = 2, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(-1, 0) } });
AddTile(new TileInfos() { Q = 3, R = 1, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(-1, 0) } });
AddTile(new TileInfos() { Q = 4, R = 6, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(0, 1) } });
AddTile(new TileInfos() { Q = 4, R = 5, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 4, R = 4, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 4, R = 3, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 4, R = 2, TileType = TileTypes.Forest });
AddTile(new TileInfos() { Q = 4, R = 1, TileType = TileTypes.Forest });
AddTile(new TileInfos() { Q = 4, R = 0, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(0, -1) } });
AddTile(new TileInfos() { Q = 5, R = 4, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 5, R = 3, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 5, R = 2, TileType = TileTypes.Forest });
AddTile(new TileInfos() { Q = 5, R = 1, TileType = TileTypes.Forest });
AddTile(new TileInfos() { Q = 5, R = 0, TileType = TileTypes.Forest });
AddTile(new TileInfos() { Q = 5, R = -1, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(-1, 0), new AxialCoords(0, -1), new AxialCoords(1, -1) } });
AddTile(new TileInfos() { Q = 6, R = 4, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(0, 1) } });
AddTile(new TileInfos() { Q = 6, R = 3, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 6, R = 2, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 6, R = 1, TileType = TileTypes.Forest });
AddTile(new TileInfos() { Q = 6, R = 0, TileType = TileTypes.Forest });
AddTile(new TileInfos() { Q = 6, R = -1, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 7, R = 3, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(0, 1) } });
AddTile(new TileInfos() { Q = 7, R = 2, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 7, R = 1, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 7, R = 0, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 7, R = -1, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(1, -1) } });
AddTile(new TileInfos() { Q = 8, R = 2, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(0, 1) } });
AddTile(new TileInfos() { Q = 8, R = 1, TileType = TileTypes.Hut });
AddTile(new TileInfos() { Q = 8, R = 0, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 8, R = -1, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(1, -1) } });
AddTile(new TileInfos() { Q = 9, R = 1, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 9, R = 0, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 9, R = -1, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(1, -1) } });
AddTile(new TileInfos() { Q = 10, R = 1, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(0, 1) } });
AddTile(new TileInfos() { Q = 10, R = 0, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 10, R = -1, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 11, R = 1, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(0, 1) } });
AddTile(new TileInfos() { Q = 11, R = 0, TileType = TileTypes.MoaiCarry });
AddTile(new TileInfos() { Q = 11, R = -1, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(1, -1) } });
AddTile(new TileInfos() { Q = 12, R = 0, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(0, 1) } });
AddTile(new TileInfos() { Q = 12, R = -1, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 13, R = 0, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(0, 1) } });
AddTile(new TileInfos() { Q = 13, R = -1, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 13, R = -2, TileType = TileTypes.Basic });
AddTile(new TileInfos() { Q = 14, R = -1, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(1, 0) } });
AddTile(new TileInfos() { Q = 14, R = -2, TileType = TileTypes.Basic, AhusAccess = new List<AxialCoords>() { new AxialCoords(1, -1) } });
}
private void AddTile(TileInfos t)
{
_tiles.Add(Index(t.Q, t.R), t);
}
private int Index(int q, int r)
{
return q * width + r;
}
} }

View File

@@ -5,4 +5,12 @@ namespace Giants.Core;
/// </summary> /// </summary>
public class TileInfos public class TileInfos
{ {
public int Q { get; init; }
public int R { get; init; }
public TileTypes TileType { get; init; } = TileTypes.Unknown;
/// <summary> La liste des directions dans laquel un ahu est accessible depuis cet tile </summary>
public ICollection<AxialCoords> AhusAccess { get; init; } = new List<AxialCoords>();
} }

View File

@@ -1,5 +0,0 @@
namespace Giants.Core;
public class TilePosition
{
}

View File

@@ -0,0 +1,19 @@
namespace Giants.Core;
public enum TileTypes
{
/// <summary> Tile inconnu </summary>
Unknown,
/// <summary> Tile de type de base, rien de spécial</summary>
Basic,
/// <summary> Une foret qui fourni les billots </summary>
Forest,
/// <summary> La tuile du village, recruter des ouvriers </summary>
Village,
/// <summary> Carriere de moai </summary>
MoaiCarry,
/// <summary> Carriere de chapeau </summary>
HatCarry,
/// <summary> Maison du magicien </summary>
Hut
}

View File

@@ -1,16 +1,41 @@
namespace Giants.Infrastructure; namespace Giants.Infrastructure;
using Giants.Core;
using Giants.Core.Interfaces; using Giants.Core.Interfaces;
using HexagonalLib; using HexagonalLib;
using HexagonalLib.Coordinates;
public class HexagonalGridImpl : IHexagonalGrid public class HexagonalGridImpl : IHexagonalGrid
{ {
private readonly HexagonalGrid _grid; private HexagonalGrid _grid;
public HexagonalGridImpl() /// <inheritdoc/>
public void Init(IHexagonalGrid.HexStyle style = IHexagonalGrid.HexStyle.PointyOdd)
{ {
_grid = new HexagonalGrid(HexagonalGridType.PointyEven, 1.0f); _grid = new HexagonalGrid(ConvertGridType(style), 1.0f);
}
public ICollection<AxialCoords> GetNeighbours(AxialCoords coords)
{
var result = new List<AxialCoords>();
foreach (var hex in _grid.GetNeighbors(new Axial(coords.Q, coords.R)))
{
result.Add(new AxialCoords(hex.Q, hex.R));
}
return result;
}
private HexagonalGridType ConvertGridType(IHexagonalGrid.HexStyle style)
{
return style switch
{
IHexagonalGrid.HexStyle.PointyEven => HexagonalGridType.PointyEven,
IHexagonalGrid.HexStyle.FlatEven => HexagonalGridType.FlatEven,
IHexagonalGrid.HexStyle.PointyOdd => HexagonalGridType.PointyOdd,
IHexagonalGrid.HexStyle.FlatOdd => HexagonalGridType.FlatOdd,
_ => throw new ArgumentOutOfRangeException(nameof(style), $"Unexpected grid style : {style}"),
};
} }
} }

View File

@@ -15,9 +15,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="nunit" Version="3.12.0" /> <PackageReference Include="nunit" Version="4.4.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" /> <PackageReference Include="NUnit3TestAdapter" Version="6.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -0,0 +1,40 @@
namespace Giants.Core.Tests;
using Giants.Application;
using Giants.Core.Commands;
using Giants.Core.Interfaces;
using Giants.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
public class ApplicationTests
{
private readonly IMatchRepository _repo;
public ApplicationTests()
{
IHexagonalGrid _grid = new HexagonalGridImpl();
BoardLayout layout = new BoardLayout(_grid);
_repo = new MatchRepositoryMock(layout);
}
[Fact]
public void ApplicationCreationExample()
{
GiantApplication app = new GiantApplication();
}
[Fact]
public void TryingServiceInjection()
{
// creation des instances
var serviceCollection = new ServiceCollection();
serviceCollection.AddScoped(repo => _repo);
// Ajout des commandes disponibles
serviceCollection.AddScoped<NewMatchCommand>();
//Test d'injection
var serviceProvider = serviceCollection.BuildServiceProvider();
NewMatchCommand? command = serviceProvider.GetService<NewMatchCommand>();
}
}

View File

@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.4" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.7" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Src\Giants.Application\Giants.Application.csproj" />
<ProjectReference Include="..\..\Src\Giants.Core\Giants.Core.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,12 +0,0 @@
namespace Giants.Core.Tests;
using Giants.Application;
public class ApplicationTests
{
[Fact]
public void ApplicationCreationExample()
{
GiantApplication app = new GiantApplication();
}
}

View File

@@ -0,0 +1,50 @@
namespace Giants.Core.Tests;
using Giants.Application;
using Giants.Core.Commands;
using Giants.Core.Interfaces;
using Giants.Infrastructure;
public class GetMatchCommandTest
{
private readonly IMatchRepository _repo;
public GetMatchCommandTest()
{
IHexagonalGrid _grid = new HexagonalGridImpl();
BoardLayout layout = new BoardLayout(_grid);
_repo = new MatchRepositoryMock(layout);
var match1 = _repo.CreateMatch();
}
[Fact]
public void GetMatchNotExisting()
{
Random random = new Random(1);
GetMatchCommand command = new GetMatchCommand(_repo)
{
MatchId = 2,
Random = random
};
GetMatchResult result = command.Execute();
Assert.False(result.Success);
Assert.Null(result.Match);
}
[Fact]
public void GetMatchSimple()
{
Random random = new Random(1);
GetMatchCommand command = new GetMatchCommand(_repo)
{
MatchId = 1,
Random = random
};
GetMatchResult result = command.Execute();
Assert.True(result.Success);
Assert.NotNull(result.Match);
}
}

View File

@@ -3,15 +3,24 @@ namespace Giants.Core.Tests;
using Giants.Application; using Giants.Application;
using Giants.Core.Commands; using Giants.Core.Commands;
using Giants.Core.Interfaces; using Giants.Core.Interfaces;
using Giants.Infrastructure;
public class NewMatchCommandTest public class NewMatchCommandTest
{ {
private readonly IMatchRepository _repo = new MatchRepositoryMock(); private readonly IMatchRepository _repo;
public NewMatchCommandTest()
{
IHexagonalGrid _grid = new HexagonalGridImpl();
BoardLayout layout = new BoardLayout(_grid);
_repo = new MatchRepositoryMock(layout);
}
[Fact] [Fact]
public void CreateBasicMatch() public void CreateBasicMatch()
{ {
NewMatchCommand command = new NewMatchCommand(_repo); Random random = new Random(1);
NewMatchCommand command = new NewMatchCommand(_repo) { Random = random };
NewMatchResult result = command.Execute(); NewMatchResult result = command.Execute();
Assert.True(result.Success); Assert.True(result.Success);
} }
@@ -19,12 +28,13 @@ public class NewMatchCommandTest
[Fact] [Fact]
public void TwoNewMatchShouldHaveDifferentID() public void TwoNewMatchShouldHaveDifferentID()
{ {
NewMatchCommand command = new NewMatchCommand(_repo); Random random = new Random(1);
NewMatchCommand command = new NewMatchCommand(_repo) { Random = random };
NewMatchResult result = command.Execute(); NewMatchResult result = command.Execute();
Assert.True(result.Success); Assert.True(result.Success);
Assert.NotNull(result.Match); Assert.NotNull(result.Match);
NewMatchCommand command2 = new NewMatchCommand(_repo); NewMatchCommand command2 = new NewMatchCommand(_repo) { Random = random };
NewMatchResult result2 = command2.Execute(); NewMatchResult result2 = command2.Execute();
Assert.True(result2.Success); Assert.True(result2.Success);
Assert.NotNull(result2.Match); Assert.NotNull(result2.Match);

View File

@@ -0,0 +1,115 @@
using Giants.Application;
using Giants.Core.Commands;
using Giants.Core.Enums;
using Giants.Core.Interfaces;
using Giants.Infrastructure;
namespace Giants.Core.Tests;
public class PrepareMatchCommandTest
{
private readonly IMatchRepository _repo;
public PrepareMatchCommandTest()
{
IHexagonalGrid _grid = new HexagonalGridImpl();
BoardLayout layout = new BoardLayout(_grid);
_repo = new MatchRepositoryMock(layout);
}
[Fact]
void SimpleInit5Players()
{
Random random = new Random(1);
NewMatchCommand command = new NewMatchCommand(_repo) { Random = random };
NewMatchResult result = command.Execute();
Match? m = result.Match;
Assert.NotNull(m);
PrepareMatchCommand prepCommand = new PrepareMatchCommand() { InputMatch = m, PlayerIDs = new List<int>() { 12, 15, 5, 14, 9 }, Random = random };
var resultPrep = prepCommand.Execute();
Assert.True(resultPrep.Success);
Assert.NotNull(resultPrep?.Match);
for (int i = 0; i < 5; i++)
{
Player? p = resultPrep.Match.GetPlayer(i);
Assert.NotNull(p);
Assert.Equal(0, p.NbVisibleTribalTokenCount);
Assert.Equal(2, p.NbHiddenTribalTokenCount);
Assert.Equal(4, p.NbUrnTribalTokenCount);
Assert.Equal(5, p.NbHiddenBase);
Assert.Equal(p.HiddenPosition, resultPrep.Match.GetPiece(p.Chef));
Assert.Equal(p.HiddenPosition, resultPrep.Match.GetPiece(p.Shaman));
Assert.Equal(1, p.Workers.Count(w => resultPrep.Match.GetPiece(w) == p.HiddenPosition));
Assert.Equal(5, p.Workers.Count(w => resultPrep.Match.GetPiece(w) == Enums.PiecePosition.Urne));
Assert.Equal(0, p.Score);
Assert.NotEqual(PiecePosition.boite, resultPrep.Match.GetPiece(PieceIndex.StartPlayer));
}
}
[Fact]
void SimpleInit4Players()
{
Random random = new Random(1);
NewMatchCommand command = new NewMatchCommand(_repo) { Random = random };
NewMatchResult result = command.Execute();
Match? m = result.Match;
Assert.NotNull(m);
PrepareMatchCommand prepCommand = new PrepareMatchCommand() { InputMatch = m, PlayerIDs = new List<int>() { 12, 15, 5, 14 }, Random = random };
var resultPrep = prepCommand.Execute();
Assert.True(resultPrep.Success);
Assert.NotNull(resultPrep?.Match);
for (int i = 0; i < 4; i++)
{
Player? p = resultPrep.Match.GetPlayer(i);
Assert.NotNull(p);
Assert.Equal(0, p.NbVisibleTribalTokenCount);
Assert.Equal(2, p.NbHiddenTribalTokenCount);
Assert.Equal(4, p.NbUrnTribalTokenCount);
Assert.Equal(6, p.NbHiddenBase);
Assert.Equal(p.HiddenPosition, resultPrep.Match.GetPiece(p.Chef));
Assert.Equal(p.HiddenPosition, resultPrep.Match.GetPiece(p.Shaman));
Assert.Equal(1, p.Workers.Count(w => resultPrep.Match.GetPiece(w) == p.HiddenPosition));
Assert.Equal(5, p.Workers.Count(w => resultPrep.Match.GetPiece(w) == Enums.PiecePosition.Urne));
Assert.Equal(0, p.Score);
Assert.NotEqual(PiecePosition.boite, resultPrep.Match.GetPiece(PieceIndex.StartPlayer));
}
}
[Fact]
void SimpleInit3Players()
{
Random random = new Random(1);
NewMatchCommand command = new NewMatchCommand(_repo) { Random = random };
NewMatchResult result = command.Execute();
Match? m = result.Match;
Assert.NotNull(m);
PrepareMatchCommand prepCommand = new PrepareMatchCommand() { InputMatch = m, PlayerIDs = new List<int>() { 12, 15, 5 }, Random = random };
var resultPrep = prepCommand.Execute();
Assert.True(resultPrep.Success);
Assert.NotNull(resultPrep?.Match);
for (int i = 0; i < 3; i++)
{
Player? p = resultPrep.Match.GetPlayer(i);
Assert.NotNull(p);
Assert.Equal(0, p.NbVisibleTribalTokenCount);
Assert.Equal(2, p.NbHiddenTribalTokenCount);
Assert.Equal(4, p.NbUrnTribalTokenCount);
Assert.Equal(7, p.NbHiddenBase);
Assert.Equal(p.HiddenPosition, resultPrep.Match.GetPiece(p.Chef));
Assert.Equal(p.HiddenPosition, resultPrep.Match.GetPiece(p.Shaman));
Assert.Equal(1, p.Workers.Count(w => resultPrep.Match.GetPiece(w) == p.HiddenPosition));
Assert.Equal(5, p.Workers.Count(w => resultPrep.Match.GetPiece(w) == Enums.PiecePosition.Urne));
Assert.Equal(0, p.Score);
Assert.NotEqual(PiecePosition.boite, resultPrep.Match.GetPiece(PieceIndex.StartPlayer));
}
}
}

View File

@@ -0,0 +1,67 @@
using Giants.Core.Enums;
using Giants.Core.Interfaces;
using Giants.Infrastructure;
namespace Giants.Core.Tests;
public class BoardLayoutTests
{
[Fact]
public void TestNeighbour()
{
IHexagonalGrid grid = new HexagonalGridImpl();
BoardLayout layout = new BoardLayout(grid);
var test = layout.GetNeighbours(new AxialCoords(2, 6)).ToList();
foreach (var voisin in new List<AxialCoords>() {
new AxialCoords(3,5),
new AxialCoords(1,6),
new AxialCoords(3,6),
new AxialCoords(2,5),
new AxialCoords(2,7),
})
{
Assert.Contains(voisin, test);
}
Assert.Equal(5, test.Count);
}
[Fact]
public void TestNeighbourWhenAhu()
{
IHexagonalGrid grid = new HexagonalGridImpl();
BoardLayout layout = new BoardLayout(grid);
var test = layout.GetNeighbours(new AxialCoords(14, -2)).ToList();
foreach (var voisin in new List<AxialCoords>() {
new AxialCoords(13,-2),
new AxialCoords(13,-1),
new AxialCoords(14,-1),
})
{
Assert.Contains(voisin, test);
}
Assert.Equal(3, test.Count);
}
[Fact]
public void CheckIndexToEnum()
{
IHexagonalGrid grid = new HexagonalGridImpl();
BoardLayout layout = new BoardLayout(grid);
Assert.Equal(PiecePosition.tile144, layout.FromTileIndex(144));
}
[Fact]
public void CheckForestQuantities()
{
IHexagonalGrid grid = new HexagonalGridImpl();
BoardLayout layout = new BoardLayout(grid);
int forest1Index = layout.ForestIndex(new AxialCoords(4, 2));
Assert.Equal(0, forest1Index);
int qteForest1 = layout.ForestQte(forest1Index);
Assert.Equal(5, qteForest1);
}
}

View File

@@ -0,0 +1,34 @@
using System.Reflection;
using Giants.Application;
using Giants.Core.Interfaces;
using Giants.Infrastructure;
namespace Giants.Core.Tests;
public class MatchTests
{
private readonly IMatchRepository _repo;
public MatchTests()
{
IHexagonalGrid _grid = new HexagonalGridImpl();
BoardLayout layout = new BoardLayout(_grid);
_repo = new MatchRepositoryMock(layout);
var match1 = _repo.CreateMatch();
}
[Fact]
public void MatchClone()
{
Match? match = _repo.CreateMatch();
Assert.NotNull(match);
match.AssignPiece(Enums.PieceIndex.StartPlayer, Enums.PiecePosition.player1Visible);
Match clone = match.Clone();
Assert.Equal(clone, match);
}
}

View File

@@ -8,10 +8,10 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2" /> <PackageReference Include="coverlet.collector" Version="6.0.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="xunit" Version="2.9.2" /> <PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" /> <PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

16
renovate.json Normal file
View File

@@ -0,0 +1,16 @@
{
"extends": [
"config:base"
],
"packageRules": [
{
"updateTypes": [
"minor",
"patch",
"pin",
"digest"
],
"automerge": false
}
]
}