Aller au contenu principal

UnoAdventure

Consignes

Ce travail pratique de soutien fait office d'examen blanc pour vous préparer à l'épreuve finale. Il est conçu pour être réalisé en 3 heures, mais ne vous inquiétez pas si vous ne le terminez pas complètement - il est volontairement un peu plus long que l'examen réel.

L'objectif est de vous permettre de réviser et de consolider vos acquis en programmation C#. N'hésitez pas à poser des questions sur Discord si vous rencontrez des difficultés.

Voici un TP de soutien, faisant office d'exam blanc, vous étant proposé pour préparer l'exam. Ce Tp est censé pouvoir être réalisé en 3h de temps, cependant aucun stress si vous ne l'avez pas fini, il est légèrement plus long que l'exam.

Bonnes révisions et n'hésitez pas à poser des questions au besoin, que ce soit sur discord.

Architecture

À la fin, votre dépôt git doit suivre cette architecture :

.
├── .gitignore
├── README
├── UnoAdventure
│ ├── Cards
│ │ ├── BasicCard.cs
│ │ ├── Card.cs
│ │ ├── JokerCard.cs
│ │ └── SpecialCard.cs
│ ├── Enums.cs
│ ├── GameManager.cs
│ ├── Player.cs
│ ├── Program.cs
│ ├── UnoAdventure.csproj
│ └── UnoException.cs
└── UnoAdventure.sln

Vérification de l'arborescence : Vous pouvez vérifier l'arborescence actuelle de votre dépôt avec la commande suivante :

tree . -I 'obj|bin|.idea|.git' -a

Exigences importantes avant soumission :

  • Remplacez évidemment prenom.nom par votre login.
  • Le fichier README est obligatoire.
  • Le fichier .gitignore est obligatoire.
  • Supprimez tous les tests personnels de votre code, sauf ceux du dossier Tests.
  • Les prototypes donnés doivent être strictement respectés.
  • Le code DOIT compiler ! Sinon vous n'obtiendrez pas de note.

Exemple de création de projet :

dotnet new sln --name UnoAdventure
dotnet new console -n UnoAdventure -f net7.0 -lang 'C#'
dotnet sln add UnoAdventure/UnoAdventure.csproj

Fundamentals

File: UnoException.cs

UnoException

Ceci est une exception que nous utiliserons tout au long du TP.

Copiez là dans UnoException.cs

Prototype
public class UnoException : Exception { }

File: Enums.cs

ColorEnum

Ceci est une énumération qui représente les quatre couleurs des cartes de Uno.

Vous devez définir les couleurs suivantes, leur associant la valeur entre parenthèses.

  • ColorGreen (0)
  • ColorRed (1)
  • ColorBlue (2)
  • ColorYellow (3)

File: Card/Card.cs

Fields

Ici, nous allons définir une classe Card qui représente une carte de Uno. Nous définirons les différents types de cartes juste après.

La classe Card doit avoir les attributs suivants :

  • Un attrubut privé Value de type string qui représente la valeur de la carte (exemple: "7", "Reverse", ect...).
Constructeur

La classe Card doit avoir un constructeur qui initialise l'attribut Value à partir de la cardValue passée en paramètre.

Prototype
public Card(string cardValue) { }

Wait the next function if you want to test properly the constructor.

GetCardValue

La classe Card doit avoir une méthode GetCardValue qui retourne l'attribut Value de la carte.

Prototype
public string GetCardValue() { }
Test
Card card = new Card("7");
Console.WriteLine(card.GetCardValue()); // Affiche "7"
Card card2 = new Card("Reverse");
Console.WriteLine(card2.GetCardValue()); // Affiche "Reverse"

File: Card/BasicCard.cs

Fields

Ici, nous allons définir une classe BasicCard qui représente une carte de Uno avec une valeur numérique (exemple: 6 rouge).

La classe BasicCard doit hériter de Card.

La classe BasicCard doit avoir les attributs suivants :

  • Un attribut public Color de type ColorEnum qui représente la couleur de la carte.
Constructeur

La classe BasicCard doit avoir un constructeur qui initialise les attributs Value et Color à partir de la cardValue et cardColor passés en paramètre.

Attention, la valeur d'une carte basique ne peut pas excéder une taille de 1 et contenir une autre valeur qu'un chiffre. Sinon, levez une UnoException.

Prototype
public BasicCard(string cardValue, ColorEnum cardColor) { }
Test
BasicCard card = new BasicCard("7", ColorEnum.ColorRed);
Console.WriteLine(card.GetCardValue()); // Affiche "7"
Console.WriteLine(card.Color); // Affiche "ColorRed"
BasicCard card2 = new BasicCard("Reverse", ColorEnum.ColorRed); // Lève une UnoException

File: Card/SpecialCard.cs

Fields

Ici, nous allons définir une classe SpecialCard qui représente une carte de Uno spéciale (exemple: "Reverse" bleue).

La classe SpecialCard doit hériter de Card.

La classe SpecialCard doit avoir les attributs suivants :

  • Un attribut public Color de type ColorEnum qui représente la couleur de la carte.
Constructeur

La classe SpecialCard doit avoir un constructeur qui initialise les attributs Value et Color à partir de la cardValue et cardColor passés en paramètre.

Attention, la valeur d'une carte spéciale ne peut etre que "Skip", "PickTwo" ou "Reverse".

Prototype
public SpecialCard(string cardValue, ColorEnum cardColor) { }
Test
SpecialCard card = new SpecialCard("Reverse", ColorEnum.ColorBlue);
Console.WriteLine(card.GetCardValue()); // Affiche "Reverse"
Console.WriteLine(card.Color); // Affiche "ColorBlue"
SpecialCard card2 = new SpecialCard("2", ColorEnum.ColorGreen); // Lève une UnoException

File: Card/JokerCard.cs

Fields

Ici, nous allons définir une classe JokerCard qui représente une carte de Uno spéciale (exemple: "Joker").

La classe JokerCard doit hériter de Card.

La classe JokerCard doit avoir les attributs suivants :

  • Un attribut privé _penalty de type ushort qui représente la pénalité de la carte. (exemple: +4)
Constructeur

La classe JokerCard doit avoir un constructeur qui initialise les attributs Value et _penalty à partir de penalty passé en paramètre.

La valeur d'une carte Joker est "Joker{penalty}".

La pénalité doit être un multiple de 2 et ne doit pas être supérieure (strict) à 8.

Prototype
public JokerCard(ushort penalty) { }
Test
JokerCard card = new JokerCard(4);
Console.WriteLine(card.GetCardValue()); // Affiche "Joker4"
JokerCard card2 = new JokerCard(0);
Console.WriteLine(card2.GetCardValue()); // Affiche "Joker0"
JokerCard card3 = new JokerCard(7); // Lève une UnoException

File: Player.cs

Propriétés

Ici, nous allons définir une classe Player qui représente un joueur de Uno.

La classe Player doit avoir les propriétés suivantes :

  • Une propriété publique Name de type string qui représente le nom du joueur (n'ayant qu'un getter).
  • Une propriété publique Hand de type Card[] qui représente la main du joueur (ayant un getter et un setter).
  • Une propriété publique NbCards de type ushort n'ayant qu'un getter qui doit renvoyer le nombre de cartes que le joueur a dans sa main.
astuce

Vous devez changer le getter de base de NbCards pour qu'il puisse vous renvoyer le nombre de cartes du joueur.

Constructeur

La classe Player doit avoir un constructeur qui initialise le Name à partir du name passé en paramètre.

La main du joueur doit être vide à sa création (tableau de taille 0).

Prototype
public Player(string name) { }
Test
Player player = new Player("Alice");
Console.WriteLine(player.Name); // Affiche "Alice"
Console.WriteLine(player.NbCards); // Affiche 0
GetNumberOfCardsByColor

La classe Player doit avoir une méthode GetNumberOfCardsByColor qui retourne un dictionnaire contenant le nombre de cartes de chaque couleur que le joueur possède.

Les clés du dictionnaire sont les couleurs des cartes et les valeurs associées sont le nombre de cartes de cette couleur.

Prototype
public Dictionary<ColorEnum, ushort> GetNumberOfCardsByColor() { }
Test
Player player = new Player("Alice");
player.Hand = new Card[] { new BasicCard("7", ColorEnum.ColorRed), new SpecialCard("Reverse", ColorEnum.ColorBlue) };
Dictionary<ColorEnum, ushort> cardsByColor = player.GetNumberOfCardsByColor();
Console.WriteLine(cardsByColor[ColorEnum.ColorRed]); // Affiche 1
Console.WriteLine(cardsByColor[ColorEnum.ColorBlue]); // Affiche 1
Console.WriteLine(cardsByColor[ColorEnum.ColorGreen]); // Affiche 0
Console.WriteLine(cardsByColor[ColorEnum.ColorYellow]); // Affiche 0
GetBestColor

La classe Player doit avoir une méthode GetBestColor qui retourne la couleur la plus présente dans la main du joueur.

Si le joueur a autant de cartes de chaque couleur, la méthode doit retourner la couleur avec la plus petite valeur associée (rien à voir avec les valeurs des cartes). Souvenez-vous, nous avons associé des valeurs à nos couleurs: 0 pour vert, 1 pour rouge, 2 pour bleu et 3 pour jaune.

Prototype
public ColorEnum GetBestColor() { }
Test
Player player = new Player("Alice");
player.Hand = new Card[] { new BasicCard("7", ColorEnum.ColorRed), new SpecialCard("Reverse", ColorEnum.ColorBlue) };
Console.WriteLine(player.GetBestColor()); // Affiche ColorRed

Player player2 = new Player("Bob");
player2.Hand = new Card[] { new SpecialCard("PickTwo", ColorEnum.ColorRed), new BasicCard("7", ColorEnum.ColorBlue), new BasicCard("8", ColorEnum.ColorBlue) };
Console.WriteLine(player2.GetBestColor()); // Affiche ColorBlue
GetCardsByColor

La classe Player doit avoir une méthode GetCardsByColor qui retourne un tableau de listes de cartes. Chaque liste de cartes représente les cartes d'une couleur.

Les listes doivent être ordonnées par leur valeur (ColorEnum). Le tableau doit être de taille 5 car il y a 4 couleurs et une liste pour les cartes joker.

Prototype
public List<Card>[] GetCardsByColor() { }
Test
Player player = new Player("Alice");
player.Hand = new Card[] { new BasicCard("7", ColorEnum.ColorRed), new BasicCard("2", ColorEnum.ColorRed), new SpecialCard("Reverse", ColorEnum.ColorBlue), new JokerCard(4) };
List<Card>[] cardsByColor = player.GetCardsByColor();
Console.WriteLine(cardsByColor[(int)ColorEnum.ColorRed].Count); // Affiche 2
Console.WriteLine(cardsByColor[(int)ColorEnum.ColorBlue].Count); // Affiche 1
Console.WriteLine(cardsByColor[(int)ColorEnum.ColorGreen].Count); // Affiche 0
Console.WriteLine(cardsByColor[(int)ColorEnum.ColorYellow].Count); // Affiche 0
Console.WriteLine(cardsByColor[4].Count); // Affiche 1
Selection Sort

Ici nous allons implémenter un algorithme de tri par sélection pour trier les cartes d'une couleur donnée dans l'ordre décroissant.

La classe Player doit avoir une méthode GetMaxIndexCard qui retourne l'index de la carte de valeur maximale dans la liste cards à partir de l'index start.

La classe Player doit aussi avoir une méthode SortCardsWithSameColor qui trie les cartes de la liste cards par ordre décroissant de valeur.

astuce

Parce que les valeurs des cartes sont des string (et qu'elles peuvent être des chiffres ou des mots), vous devez utiliser la méthode String.Compare pour comparer les valeurs des cartes.

La méthode String.Compare retourne un entier négatif si l'objet est inférieur à l'objet passé en paramètre, 0 si les deux objets sont égaux et un entier positif si l'objet est supérieur à l'objet passé en paramètre.

Nous choisirons la StringComparison.Ordinal pour comparer les valeurs des cartes.

Par exemple:

String.Compare("7", "Reverse", StringComparison.Ordinal); // Retourne un entier négatif car "7" est inférieur à "Reverse"
String.Compare("7", "7", StringComparison.Ordinal); // Retourne 0 car "7" est égal à "7"
String.Compare("Reverse", "7", StringComparison.Ordinal); // Retourne un entier positif car "Reverse" est supérieur à "7"
Prototype
public int GetMaxIndexCard(List<Card> cards, int start) { }
Test
Player player = new Player("Alice");
List<Card> cards = new List<Card> { new BasicCard("7", ColorEnum.ColorRed), new SpecialCard("Reverse", ColorEnum.ColorRed), new BasicCard("2", ColorEnum.ColorRed) };
Console.WriteLine(player.GetMaxIndexCard(cards, 0)); // Affiche 1
Console.WriteLine(player.GetMaxIndexCard(cards, 2)); // Affiche 2
Prototype
public void SortCardsWithSameColor(List<Card> cards) { }
Test
Player player = new Player("Alice");
List<Card> cards = new List<Card> { new BasicCard("7", ColorEnum.ColorRed), new SpecialCard("Reverse", ColorEnum.ColorRed), new BasicCard("2", ColorEnum.ColorRed) };
player.SortCardsWithSameColor(cards);
Console.WriteLine(cards[0].GetCardValue()); // Affiche "Reverse"
Console.WriteLine(cards[1].GetCardValue()); // Affiche "7"
Console.WriteLine(cards[2].GetCardValue()); // Affiche "2"
SortHand

La classe Player doit avoir une méthode SortHand qui trie la main du joueur par couleur et par valeur décroissante.

Vous devez utiliser la méthode GetCardsByColor et SortCardsWithSameColor pour trier les cartes par couleur et par valeur.

Vous devez ensuite reconstruire la main du joueur en concaténant les listes afin de créer un nouveau tableau.

Prototype
public void SortHand() { }
Test
Player player = new Player("Alice");
player.Hand = new Card[] { new BasicCard("7", ColorEnum.ColorRed), new SpecialCard("Reverse", ColorEnum.ColorBlue), new BasicCard("2", ColorEnum.ColorRed) };
player.SortHand();
Console.WriteLine(player.Hand[0].GetCardValue()); // Affiche "7"
Console.WriteLine(player.Hand[1].GetCardValue()); // Affiche "2"
Console.WriteLine(player.Hand[2].GetCardValue()); // Affiche "Reverse"

File: GameManager.cs

Propriétés

Ici, nous allons définir une classe GameManager qui représente une partie de Uno.

La classe GameManager doit avoir les propriétés suivantes :

  • Une propriété publique Players de type Queue<Player> qui représente les joueurs de la partie.
  • Une propriété publique Deck de type List<Card> qui représente le paquet de cartes de la partie.
  • Une propriété publique DiscardPile de type Stack<Card> qui représente la pile de défausse de la partie.

Chacune des propriétés doit avoir un getter public et setter privé, à l'exception de Deck qui doit avoir un getter public et un setter public.

Constructeur

La classe GameManager doit avoir un constructeur qui initialise les propriétés Players, Deck et DiscardPile.

Les joueurs doivent être ajoutés à la file dans l'ordre de leur création.

Le paquet de cartes doit être initialisé vide.

La pile de défausse doit être vide à la création.

Prototype
public GameManager() { }
Test
GameManager game = new GameManager();
Console.WriteLine(game.Players.Count); // Affiche 0
Console.WriteLine(game.Deck.Count); // Affiche 0
Console.WriteLine(game.DiscardPile.Count); // Affiche 0
AddPlayer

La classe GameManager doit avoir une méthode AddPlayer qui ajoute un joueur à la partie.

Prototype
public void AddPlayer(Player player) { }
Test
GameManager game = new GameManager();
Player player = new Player("Alice");
Player player2 = new Player("Bob");
game.AddPlayer(player);
game.AddPlayer(player2);
Console.WriteLine(game.Players.Count); // Affiche 2
Console.WriteLine(game.Players.Peek().Name); // Affiche "Alice"
game.Players.Dequeue();
Console.WriteLine(game.Players.Peek().Name); // Affiche "Bob"
AddPlayers

La classe GameManager doit avoir une méthode AddPlayers qui ajoute plusieurs joueurs à la partie.

Prototype
public void AddPlayers(Player[] players) { }
Test
GameManager game = new GameManager();
Player player = new Player("Alice");
Player player2 = new Player("Bob");
game.AddPlayers(new Player[] { player, player2 });
Console.WriteLine(game.Players.Count); // Affiche 2
Console.WriteLine(game.Players.Peek().Name); // Affiche "Alice"
game.Players.Dequeue();
Console.WriteLine(game.Players.Peek().Name); // Affiche "Bob"
CreateDeck

La classe GameManager doit avoir une méthode CreateDeck qui initialise le paquet de cartes de la partie.

Le paquet de cartes doit contenir deux exemplaires de toutes les cartes de Uno (4 couleurs de 0 à 9, les cartes spéciales et des jokers avec une pénalité de 0, 4, 8 uniquement).

Prototype
public void CreateDeck() { }
Test
GameManager game = new GameManager();
game.CreateDeck();
Console.WriteLine(game.Deck.Count); // Affiche 110

Proficiencies

Lorsque vous utiliserez la capacité de vos cartes, vous devrez aussi vous assurez d'enfiler le Joueur actuel dans la file de joueurs.

File: Player.cs

DrawCard

La méthode DrawCard prend en paramètre le paquet de cartes. Elle ajoute une carte au joueur en prenant la première carte du paquet (à l'index 0).

N'oubliez pas de retirer la carte du paquet.

Prototype
public void DrawCard(List<Card> deck) { }
Test
Player player = new Player("Alice");
List<Card> deck = new List<Card> { new BasicCard("6", ColorEnum.ColorRed), new BasicCard("6", ColorEnum.ColorBlue), new BasicCard("6", ColorEnum.ColorGreen) };
player.DrawCard(deck);
// player should have 1 card in his hand -> 6 red
// deck should have 2 cards -> 6 blue, 6 green
UseCard

La méthode UseCard prend en paramètre la carte à jouer et la pile de cartes. Elle ajoute la carte à la pile puis retire la carte de la main du joueur.

Prototype
public void UseCard(Card card, Stack<Card> stack) { }
Test
Player player = new Player("Alice");
player.Hand = new Card[] { new BasicCard("6", ColorEnum.ColorRed), new BasicCard("6", ColorEnum.ColorBlue) };
Stack<Card> stack = new Stack<Card>();
player.UseCard(player.Hand[0], stack);
// player should have 1 card in his hand -> 6 blue
// stack should have 1 card -> 6 red
Play

La méthode Play prend en paramètre la pile de cartes, le paquet de cartes, la file de joueurs et la couleur actuelle. Elle regarde sa main de gauche à droite, s'il peut jouer une carte, il la joue. S'il ne peut pas jouer, il pioche une carte.

Il peut jouer uniquement si la couleur de la carte est identique à la couleur actuelle ou que le chiffre est le même que la carte du dessus de la pile ou que la carte est un Joker.

La méthode doit retourner un booléen indiquant si le joueur n'a plus de cartes en main.

Prototype
public bool Play(Stack<Card> pile, List<Card> deck, Queue<Player> players, ColorEnum actualColor) { }
Test
Player player = new Player("Alice");
player.Hand = new Card[] { new BasicCard("6", ColorEnum.ColorBlue) };
Stack<Card> pile = new Stack<Card>();
pile.Push(new BasicCard("6", ColorEnum.ColorRed));
List<Card> deck = new List<Card> { new BasicCard("6", ColorEnum.ColorBlue), new BasicCard("6", ColorEnum.ColorGreen) };
Queue<Player> players = new Queue<Player>( new List<Player> { new Player("Bob"), new Player("Charlie") } );
ColorEnum actualColor = ColorEnum.ColorRed;
bool res = player.Play(pile, deck, players, actualColor);
// players should be -> Alice, Charlie, Bob ->
// Alice should have played the card and the pile should have 2 cards
// Alice should have 0 cards in her hand
// the function should return true

File: Card/SpecialCard.cs

PickTwoCard

La méthode PickTwoCard prend en paramètre le joueur actuel, la file de joueurs et le paquet de cartes. Elle retire le prochain joueur de la file, lui fait piocher deux cartes, puis remet le joueur actuel puis le prochain joueur dans la file.

Il est important de noter que le joueur actuel doit être remis dans la file avant le prochain joueur.

Prototype
public void PickTwoCard(Player actualPlayer, Queue<Player> players, List<Card> deck) { }
Test
Player actualPlayer = new Player("Alice");
actualPlayer.Hand = new Card[] { new BasicCard("7", ColorEnum.ColorRed) };
Player nextPlayer = new Player("Bob");
nextPlayer.Hand = new Card[] { new BasicCard("0", ColorEnum.ColorYellow) };
Queue<Player> players = new Queue<Player>( new List<Player> { nextPlayer, new Player("Charlie") } );
List<Card> deck = new List<Card> { new BasicCard("6", ColorEnum.ColorRed), new BasicCard("6", ColorEnum.ColorBlue), new BasicCard("6", ColorEnum.ColorGreen) };
SpecialCard card = new SpecialCard("PickTwo", ColorEnum.ColorRed);
card.PickTwoCard(actualPlayer, players, deck);
// players should be -> Bob, Alice, Charlie ->
// Bob should have 3 cards in his hand -> 0 yellow, 6 red, 6 blue
SkipCard

La méthode SkipCard prend en paramètre le joueur actuel et la file de joueurs. Elle retire le prochain joueur de la file puis le remet dans la file.

Il est important de noter que le joueur actuel doit être remis dans la file avant le prochain joueur.

Prototype
public void SkipCard(Player actualPlayer, Queue<Player> players) { }
Test
Queue<Player> players = new Queue<Player>( new List<Player> { new Player("Alice"), new Player("Bob"), new Player("Charlie") } );
Player actualPlayer = players.Dequeue();
SpecialCard card = new SpecialCard("Skip", ColorEnum.ColorRed);
card.SkipCard(actualPlayer, players);
// players should be -> Bob, Alice, Charlie ->
Console.WriteLine();
ReverseCard

La méthode ReverseCard prend en paramètre le joueur actuel et la file de joueurs. Elle inverse l'ordre des joueurs dans la file.

Il est important de noter que le joueur actuel doit être remis dans la file après l'avoir renversée.

Prototype
public void ReverseCard(Player actualPlayer, Queue<Player> players) { }
Test
Queue<Player> players = new Queue<Player>( new List<Player> { new Player("Alice"), new Player("Bob"), new Player("Charlie") } );
Player actualPlayer = players.Dequeue();
SpecialCard card = new SpecialCard("Reverse", ColorEnum.ColorRed);
card.ReverseCard(actualPlayer, players);
// players was -> Charlie, Bob ->
// players is now -> Alice, Bob, Charlie ->
UseCapacity

La méthode UseCapacity prend en paramètre le joueur actuel, la file de joueurs et le paquet de cartes. Elle appelle la méthode correspondante à la capacité de la carte.

Prototype
public void UseCapacity(Player actualPlayer, Queue<Player> players, List<Card> deck) { }

File: Card/JokerCard.cs

UseCapacity

La classe JokerCard est une carte spéciale qui permet de changer la couleur du jeu. Cependant ici nous ne gèreront pas le changement de couleur (qui se fera dans une autre fonction). Nous allons simplement faire piocher des cartes au joueur suivant en fonction du malus de la carte.

La méthode UseCapacity prend en paramètre le joueur actuel et la file de joueurs. Elle fait piocher des cartes au joueur suivant en fonction du malus de la carte.

La fonction remet ensuite le joueur actuel puis le joueur suivant dans la file.

Il est important de noter que le joueur actuel doit être remis dans la file avant le prochain joueur.

Prototype
public void UseCapacity(Player actualPlayer, Queue<Player> players, List<Card> deck) { }
Test
Queue<Player> players = new Queue<Player>( new List<Player> { new Player("Alice"), new Player("Bob"), new Player("Charlie") } );
List<Card> deck = new List<Card> { new BasicCard("6", ColorEnum.ColorRed), new BasicCard("6", ColorEnum.ColorBlue), new BasicCard("6", ColorEnum.ColorGreen) };
Player actualPlayer = players.Dequeue();
JokerCard jokerCard = new JokerCard(2);
jokerCard.UseCapacity(actualPlayer, players, deck);
// players should be -> Bob, Alice, Charlie ->
// Bob should have 2 cards in his hand -> 6 red, 6 blue
// deck should have 1 card -> 6 green

File: GameManager.cs

ShuffleDeck

La méthode ShuffleDeck mélange le paquet de cartes du joueur.

Vous devez pour cela créer un tableau à deux dimensions de cartes de 5 colonnes et avec le nombre de lignes le plus petit possible pour contenir toutes les cartes du paquet.

Vous devez ensuite parcourir le deck et placer chaque carte dans le tableau, en les remplacant colonne par colonne. (d'abord arr[0][0] puis arr[1][0] etc.)

Enfin, vous devez reconstruire le deck en parcourant le tableau (ligne par ligne) et en ajoutant chaque carte non nulle dans le deck.

Prototype
public void ShuffleDeck() { }
Test
GameManager game = new GameManager();

game.Deck = new List<Card>
{
new BasicCard("1", ColorEnum.ColorRed),
new BasicCard("2", ColorEnum.ColorBlue),
new BasicCard("3", ColorEnum.ColorGreen),
new BasicCard("4", ColorEnum.ColorYellow),
new BasicCard("5", ColorEnum.ColorRed),
new BasicCard("6", ColorEnum.ColorBlue),
new BasicCard("7", ColorEnum.ColorGreen),
new BasicCard("8", ColorEnum.ColorYellow),
new BasicCard("9", ColorEnum.ColorRed)
};

game.ShuffleDeck();

// deck should be:
// done later
// 1 ColorRed
// 3 ColorGreen
// 5 ColorRed
// 7 ColorGreen
// 9 ColorRed
// 2 ColorBlue
// 4 ColorYellow
// 6 ColorBlue
// 8 ColorYellow
CountPoints

La méthode CountPoints retourne un dictionnaire contenant les points de chaque joueur.

Chaque carte spéciale vaut 20 points, chaque carte normale vaut son chiffre et chaque Joker vaut 50 points.

Prototype
public Dictionary<Player,int> CountPoints() { }
Test
Player player1 = new Player("Alice");
player1.Hand = new Card[] { new BasicCard("6", ColorEnum.ColorRed), new BasicCard("6", ColorEnum.ColorBlue), new BasicCard("6", ColorEnum.ColorGreen) };
Player player2 = new Player("Bob");
player2.Hand = new Card[] { new SpecialCard("PickTwo", ColorEnum.ColorRed), new SpecialCard("Skip", ColorEnum.ColorBlue), new SpecialCard("Reverse", ColorEnum.ColorGreen) };
GameManager game = new GameManager();
game.AddPlayer(player1);
game.AddPlayer(player2);
Dictionary<Player,int> points = game.CountPoints();
Console.WriteLine(points[player1]); // 18
Console.WriteLine(points[player2]); // 60
DealCards

La méthode DealCards distribue 7 cartes à chaque joueur. Elle doit appeler la méthode DrawCard à chaque fois. Les cartes devront être disribuées comme dans la vraie vie. Par exemple si il y a 3 joueurs: 1-2-3-1-2-3-1-...

Prototype
public void DealCards() { }
PlayGame

La méthode PlayGame est la méthode principale du jeu. Elle doit appeler les méthodes créées précédemment pour jouer une partie complète.

Voici les différentes étapes à suivre:

  • Appeler la méthode DealCards
  • Créer la pile de défausse DiscardPile et y ajouter un 0 jaune (pour vous faciliter la tâche)
  • Créer une variable currentColor qui contiendra la couleur actuelle
  • Entrer dans une boucle infinie
    • Entrer dans une boucle tant que le paquet de cartes n'est pas vide
      • Retirer le joueur actuel de la file
      • Appeler la méthode Play du joueur actuel
      • Si le joueur n'a plus de cartes, appeler la méthode CountPoints et retourner le résultat
      • Changer la couleur actuelle en fonction de la carte du dessus de la pile. Si la carte est un Joker, utilisez alors la méthode GetBestColor du joueur ayant utilisé la carte pour changer la couleur actuelle.
    • Retirer la carte du dessus de la pile et remettre toutes les cartes de la pile dans le paquet
    • Mélanger le paquet
Prototype
public Dictionary<Player,int> PlayGame() { }