| | | 1 | | using LittleTown.Core.Actions; |
| | | 2 | | using LittleTown.Core.Exceptions; |
| | | 3 | | using LittleTown.Core.Ports; |
| | | 4 | | |
| | | 5 | | namespace LittleTown.Core; |
| | | 6 | | |
| | | 7 | | /// <summary> |
| | | 8 | | /// Represente un match de LittleTown |
| | | 9 | | /// </summary> |
| | | 10 | | public class Match |
| | | 11 | | { |
| | | 12 | | /// <summary> LE numero du tour en cours (Partant de 1) </summary> |
| | 40 | 13 | | public int CurrentTurn { get; private set; } = 1; |
| | | 14 | | |
| | | 15 | | /// <summary> l'id du joueur a qui c'est le tour de jouer</summary> |
| | 0 | 16 | | public string CurrentPlayer { get => _players[_playerTurnsOrder[_currentPlayerIndex]].PlayerName; } |
| | | 17 | | |
| | | 18 | | /// <summary> Indique si le match est terminé </summary> |
| | 30 | 19 | | public bool IsDone { get; private set; } |
| | | 20 | | |
| | | 21 | | /// <summary>la liste indiquant l'ordre des joueurs, _playerTurnsOrder[0] donne l'index du 1er joueur, _playerTurnsO |
| | 16 | 22 | | private List<int> _playerTurnsOrder = new List<int>(); |
| | | 23 | | |
| | | 24 | | private const int _minPlayerCount = 2; |
| | | 25 | | private const int _maxPlayerCount = 4; |
| | | 26 | | |
| | | 27 | | private int _maxWorkerPerPlayer; |
| | | 28 | | private int _maxBuidingPerPlayer; |
| | | 29 | | |
| | | 30 | | private readonly Board _board; |
| | | 31 | | private ICollection<Building> _buildings; |
| | | 32 | | private ICollection<Objective> _objectives; |
| | | 33 | | |
| | 16 | 34 | | private Random _random = new Random(); |
| | | 35 | | |
| | 16 | 36 | | private List<PlayerZone> _players = new(); |
| | | 37 | | private int _currentPlayerIndex; |
| | | 38 | | |
| | | 39 | | /// <summary> |
| | | 40 | | /// Constructeur d'une nouvelle partie avec un nombre de joueurs données en parametres |
| | | 41 | | /// </summary> |
| | | 42 | | /// <param name="staticData">un objet permettant de récupérer les données statiques du jeu</param> |
| | 16 | 43 | | public Match(IStaticDataGetter staticData) |
| | | 44 | | { |
| | 16 | 45 | | ArgumentNullException.ThrowIfNull(staticData); |
| | | 46 | | |
| | 16 | 47 | | _board = staticData.GetBoardAsync(1).GetAwaiter().GetResult(); |
| | 16 | 48 | | _buildings = staticData.GetBuildings(); |
| | 16 | 49 | | _objectives = staticData.GetObjectives(); |
| | 16 | 50 | | } |
| | | 51 | | |
| | | 52 | | /// <summary> Ajouter un nouveau joueur a la partie </summary> |
| | | 53 | | /// <param name="playerName">le nom du joueur</param> |
| | | 54 | | public void AddPlayer(string playerName) |
| | | 55 | | { |
| | 44 | 56 | | if (_players.Count < _maxPlayerCount) |
| | | 57 | | { |
| | 84 | 58 | | if (_players.Any(p => p.PlayerName == playerName)) |
| | | 59 | | { |
| | 2 | 60 | | throw new MatchConfigException("Un joueur existe déjà avec ce nom"); |
| | | 61 | | } |
| | 40 | 62 | | _players.Add(new PlayerZone() |
| | 40 | 63 | | { |
| | 40 | 64 | | PlayerName = playerName |
| | 40 | 65 | | }); |
| | | 66 | | } |
| | | 67 | | else |
| | | 68 | | { |
| | 2 | 69 | | throw new MatchConfigException("Impossible d'ajouter de nouveau joueur, la partie est pleine"); |
| | | 70 | | } |
| | | 71 | | } |
| | | 72 | | |
| | | 73 | | |
| | | 74 | | /// <summary> |
| | | 75 | | /// Demander au match d'executer une action si elle est autorisée |
| | | 76 | | /// </summary> |
| | | 77 | | /// <param name="action">l'action a réaliser</param> |
| | | 78 | | public void ExecuteAction(IAction action) |
| | | 79 | | { |
| | 14 | 80 | | ArgumentNullException.ThrowIfNull(action); |
| | | 81 | | |
| | | 82 | | //quelques vérification génériques pour savoir si l'action peut être jouée |
| | 14 | 83 | | if (IsDone) |
| | | 84 | | { |
| | 2 | 85 | | throw new MatchFinishedException("Impossible d'effectuer une action sur un match terminé"); |
| | | 86 | | } |
| | | 87 | | |
| | | 88 | | //autoriser l'action a s'executer en lui donner les getters dont elle a besoin |
| | 12 | 89 | | action.Execute(this); |
| | 12 | 90 | | } |
| | | 91 | | |
| | | 92 | | /// <summary> Initialiser la partie, il faut avoir ajouté les joueurs au préalable </summary> |
| | | 93 | | /// <exception cref="MatchConfigException"></exception> |
| | | 94 | | public void Init() |
| | | 95 | | { |
| | 14 | 96 | | int nbPlayer = _players.Count; |
| | | 97 | | |
| | 14 | 98 | | ArgumentOutOfRangeException.ThrowIfLessThan(nbPlayer, _minPlayerCount); |
| | 12 | 99 | | ArgumentOutOfRangeException.ThrowIfGreaterThan(nbPlayer, _maxPlayerCount); |
| | | 100 | | |
| | 12 | 101 | | List<int> freeObjectiveIndexs = Enumerable.Range(0, _objectives.Count).ToList(); |
| | 84 | 102 | | foreach (PlayerZone zone in _players) |
| | | 103 | | { |
| | 30 | 104 | | zone.AddObjectives(GetRandomObjectives(nbPlayer switch |
| | 30 | 105 | | { |
| | 16 | 106 | | 2 => 4, |
| | 6 | 107 | | 3 => 3, |
| | 8 | 108 | | 4 => 2, |
| | 0 | 109 | | _ => throw new MatchConfigException("Mauvais nombre de joueurs lors Workers") |
| | 30 | 110 | | }, freeObjectiveIndexs)); |
| | 30 | 111 | | zone.AddRessources(Enums.ResourceType.Piece, 3); |
| | | 112 | | } |
| | | 113 | | |
| | 12 | 114 | | _maxWorkerPerPlayer = nbPlayer switch |
| | 12 | 115 | | { |
| | 8 | 116 | | 2 => 5, |
| | 2 | 117 | | 3 => 4, |
| | 2 | 118 | | 4 => 3, |
| | 0 | 119 | | _ => throw new MatchConfigException("Mauvais nombre de joueurs lors Workers") |
| | 12 | 120 | | }; |
| | | 121 | | |
| | 12 | 122 | | _maxBuidingPerPlayer = nbPlayer switch |
| | 12 | 123 | | { |
| | 8 | 124 | | 2 => 7, |
| | 2 | 125 | | 3 => 6, |
| | 2 | 126 | | 4 => 6, |
| | 0 | 127 | | _ => throw new MatchConfigException("Mauvais nombre de joueurs lors building") |
| | 12 | 128 | | }; |
| | | 129 | | |
| | | 130 | | // preparer l'ordre des joueurs |
| | 12 | 131 | | int index = _random.Next(nbPlayer); |
| | 84 | 132 | | for (int i = 0; i < nbPlayer; ++i) |
| | | 133 | | { |
| | 30 | 134 | | _playerTurnsOrder.Add(index++); |
| | 30 | 135 | | if (index >= nbPlayer) |
| | 12 | 136 | | index = 0; |
| | | 137 | | } |
| | | 138 | | |
| | 12 | 139 | | _currentPlayerIndex = 0; |
| | | 140 | | |
| | 12 | 141 | | } |
| | | 142 | | |
| | | 143 | | /// <summary> Permet de récuperer une player zone(une copie) </summary> |
| | | 144 | | /// <param name="playerName">le nom ou ID du joueur</param> |
| | | 145 | | /// <returns></returns> |
| | | 146 | | public PlayerZone GetPlayerZone(string playerName) |
| | | 147 | | { |
| | 16 | 148 | | var value = _players.Where(p => p.PlayerName == playerName).FirstOrDefault(); |
| | | 149 | | |
| | | 150 | | |
| | 6 | 151 | | if (null == value) |
| | 2 | 152 | | throw new ArgumentException("playerID is out of bound"); |
| | | 153 | | |
| | 4 | 154 | | return value.Clone() as PlayerZone ?? throw new ArgumentException("Cast exception in GetPlayerZone"); ; |
| | | 155 | | } |
| | | 156 | | |
| | | 157 | | private List<Objective> GetRandomObjectives(int number, List<int> freeIndex) |
| | | 158 | | { |
| | 30 | 159 | | List<Objective> result = new List<Objective>(); |
| | 256 | 160 | | for (int i = 0; i < number; i++) |
| | | 161 | | { |
| | 98 | 162 | | int randomIndex = _random.Next(freeIndex.Count); |
| | 98 | 163 | | int cardIndex = freeIndex[randomIndex]; |
| | 98 | 164 | | freeIndex.RemoveAt(randomIndex); |
| | 98 | 165 | | result.Add(_objectives.ElementAt(randomIndex)); |
| | | 166 | | } |
| | 30 | 167 | | return result; |
| | | 168 | | } |
| | | 169 | | /// <summary> Changer le joueur en cours pour passer au suivant </summary> |
| | | 170 | | public void NextPlayer() |
| | | 171 | | { |
| | 12 | 172 | | _currentPlayerIndex++; |
| | 12 | 173 | | if (_currentPlayerIndex >= _players.Count) |
| | | 174 | | { |
| | 6 | 175 | | _currentPlayerIndex = 0; |
| | 6 | 176 | | CurrentTurn++; |
| | | 177 | | } |
| | 12 | 178 | | if (CurrentTurn >= 4) |
| | | 179 | | { |
| | 2 | 180 | | IsDone = true; |
| | | 181 | | } |
| | 12 | 182 | | } |
| | | 183 | | } |