diff --git a/Graphics/plan.pdn b/Graphics/plan.pdn new file mode 100644 index 0000000..a8458a0 Binary files /dev/null and b/Graphics/plan.pdn differ diff --git a/Src/Giants.Application/Src/MatchRepositoryMock.cs b/Src/Giants.Application/Src/MatchRepositoryMock.cs index e71a5d9..cc53218 100644 --- a/Src/Giants.Application/Src/MatchRepositoryMock.cs +++ b/Src/Giants.Application/Src/MatchRepositoryMock.cs @@ -9,7 +9,7 @@ namespace Giants.Application; /// public class MatchRepositoryMock : IMatchRepository { - private readonly IHexagonalGrid _gridLayout; + private readonly BoardLayout _boardLayout; private static int _lastId = 1; private Dictionary _matchs = new Dictionary(); @@ -17,9 +17,9 @@ public class MatchRepositoryMock : IMatchRepository /// /// constructeur /// - public MatchRepositoryMock() + public MatchRepositoryMock(BoardLayout boardLayout) { - _gridLayout = new HexagonalGridImpl(); + _boardLayout = boardLayout; } /// @@ -35,9 +35,10 @@ public class MatchRepositoryMock : IMatchRepository /// public Match CreateMatch() { - Match result = new Match(_gridLayout) + Match result = new Match() { - Id = _lastId++ + Id = _lastId++, + Board = _boardLayout, }; AddStaticData(result); @@ -52,4 +53,8 @@ public class MatchRepositoryMock : IMatchRepository } + public void SetMapData(IHexagonalGrid grid) + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/Src/Giants.Core/Src/Commands/GetMatchCommand.cs b/Src/Giants.Core/Src/Commands/GetMatchCommand.cs new file mode 100644 index 0000000..63a4f41 --- /dev/null +++ b/Src/Giants.Core/Src/Commands/GetMatchCommand.cs @@ -0,0 +1,43 @@ + +using Giants.Core.Interfaces; + +namespace Giants.Core.Commands; + +/// +/// Logique metier qui permet d'ajouter les données statiques aux matchs qui arrivent du repository +/// +public class GetMatchCommand : BaseCommand +{ + private IMatchRepository _repo; + + /// L'id du match a récupérer + 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 +{ + /// Le match si success null sinon + public Match? Match { get; init; } +} \ No newline at end of file diff --git a/Src/Giants.Core/Src/Entities/Match.cs b/Src/Giants.Core/Src/Entities/Match.cs index 2976233..bbdb5ff 100644 --- a/Src/Giants.Core/Src/Entities/Match.cs +++ b/Src/Giants.Core/Src/Entities/Match.cs @@ -11,19 +11,15 @@ namespace Giants.Core; public class Match { #region données statiques + public int Id { get; init; } - IHexagonalGrid _grid; + public required BoardLayout Board { get; init; } + #endregion #region données dynamiques #endregion - /// Construction de base - /// La grid du jeu - public Match(IHexagonalGrid grid) - { - _grid = grid; - } /// Permet de comparer des Match, cette methode est critique pour l'ia pour reduire son parcour d'arbre /// diff --git a/Src/Giants.Core/Src/Interfaces/IHexagonalGrid.cs b/Src/Giants.Core/Src/Interfaces/IHexagonalGrid.cs index d362ddb..64dc18c 100644 --- a/Src/Giants.Core/Src/Interfaces/IHexagonalGrid.cs +++ b/Src/Giants.Core/Src/Interfaces/IHexagonalGrid.cs @@ -5,5 +5,32 @@ namespace Giants.Core.Interfaces; /// public interface IHexagonalGrid { + /// + /// indique le style de grille, voir https://www.redblobgames.com/grids/hexagons/ pour des détails + /// + public enum HexStyle + { + /// Pointe vers le haut, impaire a droite + PointyOdd, + /// Pointe vers le haut, pair a droite + PointyEven, + /// Pointe vers le coté, impaire en bas + FlatOdd, + /// Pointe vers le coté, impaire en haut + FlatEven + } + + /// + /// Demande a la grille d'allouer sa taille et son type + /// + /// le style de grid + public void Init(HexStyle style = HexStyle.PointyOdd); + + /// + /// Permet de recupérer la liste des tiles voisines d'une tile fournie en parametre + /// + /// La tuile de laquelle on cherche les voisins + /// la liste des tiles voisines + public ICollection GetNeighbours(AxialCoords coords); } \ No newline at end of file diff --git a/Src/Giants.Core/Src/Interfaces/IMatchRepository.cs b/Src/Giants.Core/Src/Interfaces/IMatchRepository.cs index 4879a2b..60a08a8 100644 --- a/Src/Giants.Core/Src/Interfaces/IMatchRepository.cs +++ b/Src/Giants.Core/Src/Interfaces/IMatchRepository.cs @@ -1,7 +1,7 @@ namespace Giants.Core.Interfaces; /// -/// 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 /// public interface IMatchRepository { @@ -17,4 +17,9 @@ public interface IMatchRepository /// /// le nouveau match a son état initial Match? CreateMatch(); + + /// + /// Fournir au repository la map a assigner aux match instanciés + /// + public void SetMapData(IHexagonalGrid grid); } \ No newline at end of file diff --git a/Src/Giants.Core/Src/ValuesObjects/AxialCoords.cs b/Src/Giants.Core/Src/ValuesObjects/AxialCoords.cs new file mode 100644 index 0000000..61beb09 --- /dev/null +++ b/Src/Giants.Core/Src/ValuesObjects/AxialCoords.cs @@ -0,0 +1,19 @@ +namespace Giants.Core; + +public 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; + } +} \ No newline at end of file diff --git a/Src/Giants.Core/Src/ValuesObjects/BoardLayout.cs b/Src/Giants.Core/Src/ValuesObjects/BoardLayout.cs index 0ec0373..4a967a1 100644 --- a/Src/Giants.Core/Src/ValuesObjects/BoardLayout.cs +++ b/Src/Giants.Core/Src/ValuesObjects/BoardLayout.cs @@ -1,9 +1,109 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.RegularExpressions; +using Giants.Core.Interfaces; + namespace Giants.Core; /// /// 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 +/// noter que cette classe doit être immuable comme c'est un valueObjet, donc pas des setter autre que init /// public class BoardLayout { + + IHexagonalGrid _grid; + + Dictionary _tiles; + + int width = 16; + + public BoardLayout(IHexagonalGrid gridSystem) + { + _grid = gridSystem; + BuildDefaultBoard(); + } + + public ICollection GetNeighbours(AxialCoords coords) + { + var tmp = _grid.GetNeighbours(coords); + + return tmp.Where(t => _tiles.ContainsKey(Index(t.Q, t.R))).ToList(); + } + + [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(); + AddTile(new TileInfos() { Q = 1, R = 6, TileType = TileTypes.Basic, AhusAccess = new List() { new AxialCoords(-1, 0) } }); + AddTile(new TileInfos() { Q = 2, R = 7, TileType = TileTypes.Basic, AhusAccess = new List() { 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() { new AxialCoords(-1, 0) } }); + AddTile(new TileInfos() { Q = 2, R = 4, TileType = TileTypes.Basic, AhusAccess = new List() { new AxialCoords(-1, 0) } }); + AddTile(new TileInfos() { Q = 3, R = 6, TileType = TileTypes.Basic, AhusAccess = new List() { 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() { new AxialCoords(-1, 0) } }); + AddTile(new TileInfos() { Q = 3, R = 2, TileType = TileTypes.Basic, AhusAccess = new List() { new AxialCoords(-1, 0) } }); + AddTile(new TileInfos() { Q = 3, R = 1, TileType = TileTypes.Basic, AhusAccess = new List() { new AxialCoords(-1, 0) } }); + AddTile(new TileInfos() { Q = 4, R = 6, TileType = TileTypes.Basic, AhusAccess = new List() { 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() { 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() { 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() { 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() { 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() { new AxialCoords(1, -1) } }); + AddTile(new TileInfos() { Q = 8, R = 2, TileType = TileTypes.Basic, AhusAccess = new List() { 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() { 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() { new AxialCoords(1, -1) } }); + AddTile(new TileInfos() { Q = 10, R = 1, TileType = TileTypes.Basic, AhusAccess = new List() { 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() { 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() { new AxialCoords(1, -1) } }); + AddTile(new TileInfos() { Q = 12, R = 0, TileType = TileTypes.Basic, AhusAccess = new List() { 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() { 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() { new AxialCoords(1, 0) } }); + AddTile(new TileInfos() { Q = 14, R = -2, TileType = TileTypes.Basic, AhusAccess = new List() { 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; + } } + diff --git a/Src/Giants.Core/Src/ValuesObjects/TileInfos.cs b/Src/Giants.Core/Src/ValuesObjects/TileInfos.cs index 50ce365..5be036b 100644 --- a/Src/Giants.Core/Src/ValuesObjects/TileInfos.cs +++ b/Src/Giants.Core/Src/ValuesObjects/TileInfos.cs @@ -5,4 +5,12 @@ namespace Giants.Core; /// public class TileInfos { + public int Q { get; init; } + + public int R { get; init; } + + public TileTypes TileType { get; init; } = TileTypes.Unknown; + + /// La liste des directions dans laquel un ahu est accessible depuis cet tile + public ICollection AhusAccess { get; init; } = new List(); } \ No newline at end of file diff --git a/Src/Giants.Core/Src/ValuesObjects/TilePosition.cs b/Src/Giants.Core/Src/ValuesObjects/TilePosition.cs deleted file mode 100644 index cef932d..0000000 --- a/Src/Giants.Core/Src/ValuesObjects/TilePosition.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Giants.Core; - -public class TilePosition -{ -} \ No newline at end of file diff --git a/Src/Giants.Core/Src/ValuesObjects/TileTypes.cs b/Src/Giants.Core/Src/ValuesObjects/TileTypes.cs new file mode 100644 index 0000000..a9bfc86 --- /dev/null +++ b/Src/Giants.Core/Src/ValuesObjects/TileTypes.cs @@ -0,0 +1,19 @@ +namespace Giants.Core; + +public enum TileTypes +{ + /// Tile inconnu + Unknown, + /// Tile de type de base, rien de spécial + Basic, + /// Une foret qui fourni les billots + Forest, + /// La tuile du village, recruter des ouvriers + Village, + /// Carriere de moai + MoaiCarry, + /// Carriere de chapeau + HatCarry, + /// Maison du magicien + Hut +} \ No newline at end of file diff --git a/Src/Giants.Infrastructure/Src/HexagonalGridImpl.cs b/Src/Giants.Infrastructure/Src/HexagonalGridImpl.cs index a270b71..4fe226d 100644 --- a/Src/Giants.Infrastructure/Src/HexagonalGridImpl.cs +++ b/Src/Giants.Infrastructure/Src/HexagonalGridImpl.cs @@ -1,16 +1,41 @@ namespace Giants.Infrastructure; +using Giants.Core; using Giants.Core.Interfaces; using HexagonalLib; +using HexagonalLib.Coordinates; public class HexagonalGridImpl : IHexagonalGrid { - private readonly HexagonalGrid _grid; + private HexagonalGrid _grid; - public HexagonalGridImpl() + /// + 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 GetNeighbours(AxialCoords coords) + { + var result = new List(); + 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}"), + }; } } \ No newline at end of file diff --git a/Tests/Giants.Application.Tests/ApplicationTests.cs b/Tests/Giants.Application.Tests/ApplicationTests.cs index 1f713de..78d4c4d 100644 --- a/Tests/Giants.Application.Tests/ApplicationTests.cs +++ b/Tests/Giants.Application.Tests/ApplicationTests.cs @@ -3,10 +3,20 @@ 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() { @@ -17,10 +27,8 @@ public class ApplicationTests public void TryingServiceInjection() { // creation des instances - IMatchRepository matchRepository = new MatchRepositoryMock(); - var serviceCollection = new ServiceCollection(); - serviceCollection.AddScoped(repo => matchRepository); + serviceCollection.AddScoped(repo => _repo); // Ajout des commandes disponibles serviceCollection.AddScoped(); diff --git a/Tests/Giants.Core.Tests/Commands/GetMatchCommandTest.cs b/Tests/Giants.Core.Tests/Commands/GetMatchCommandTest.cs new file mode 100644 index 0000000..028c951 --- /dev/null +++ b/Tests/Giants.Core.Tests/Commands/GetMatchCommandTest.cs @@ -0,0 +1,45 @@ +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() + { + GetMatchCommand command = new GetMatchCommand(_repo) + { + MatchId = 2 + }; + GetMatchResult result = command.Execute(); + Assert.False(result.Success); + Assert.Null(result.Match); + } + + [Fact] + public void GetMatchSimple() + { + GetMatchCommand command = new GetMatchCommand(_repo) + { + MatchId = 1 + }; + GetMatchResult result = command.Execute(); + Assert.True(result.Success); + Assert.NotNull(result.Match); + } + +} diff --git a/Tests/Giants.Core.Tests/Commands/NewMatchCommandTest.cs b/Tests/Giants.Core.Tests/Commands/NewMatchCommandTest.cs index b0d28cd..8b323f4 100644 --- a/Tests/Giants.Core.Tests/Commands/NewMatchCommandTest.cs +++ b/Tests/Giants.Core.Tests/Commands/NewMatchCommandTest.cs @@ -3,10 +3,18 @@ namespace Giants.Core.Tests; using Giants.Application; using Giants.Core.Commands; using Giants.Core.Interfaces; +using Giants.Infrastructure; 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] public void CreateBasicMatch() diff --git a/Tests/Giants.Core.Tests/Entities/BoardLayoutTests.cs b/Tests/Giants.Core.Tests/Entities/BoardLayoutTests.cs new file mode 100644 index 0000000..5731b03 --- /dev/null +++ b/Tests/Giants.Core.Tests/Entities/BoardLayoutTests.cs @@ -0,0 +1,46 @@ +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() { + 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() { + new AxialCoords(13,-2), + new AxialCoords(13,-1), + new AxialCoords(14,-1), + }) + { + Assert.Contains(voisin, test); + } + Assert.Equal(3, test.Count); + } +} \ No newline at end of file