Mastermind
Conception de l'application
Diagramme de classes
@startuml
enum Couleur {
ROUGE
VERT
BLEU
JAUNE
NOIR
BLANC
}
enum Indicateur {
BONNEPLACE
BONNECOULEUR
}
struct Jeton {
---
---
+Jeton(couleur: Couleur)
}
Jeton *--> Couleur: +Couleur: Couleur
class Code {
---
+NbJetons: int = 0
---
+Code(tailleCode: int)
+Code(jetons: Jeton[])
+AjouterJeton(jeton: Jeton): void
+SupprimerDernierJeton(): void
+RecupererJeton(indice: int): Jeton
+Jetons(): Jeton?[]
+EstComplet(): bool
+TailleMaximale(): int
+Comparer(autreCode: Code): Indicateur[]
}
Code o--> Jeton: -lesJeton: Jeton?[]
class Plateau {
-tailleCode: int
---
+Victoire: bool = false
+Tour: int = 1
---
+Plateau(tailleCode: int, tailleGrille: int)
+GenererCodeAleatoire(): void
+EstComplet(): bool
+AjouterCode(code: Code): void
+EstBonCode(code: Code): bool
+Grille(): Jeton?[][]
+Indicateurs(): Indicateur[][]
}
Plateau *--> Code: -codeSecret: Code
Plateau o--> Code: -grille: Code?[]
Plateau *--> Indicateur: -indicateurs: Indicateur[][]
class Joueur {
---
+Nom: string
---
+Joueur(nom: string, plateau: Plateau)
}
Joueur *--> Plateau: +Plateau: Plateau
interface IRegles {
---
+Nom: string
+TourMaximum: int
+TailleCodeMaximum: int
+NbJoueurs: int
+NbJoueursMaximum: int
---
+AjouterJoueur(joueur: string): Joueur
+JoueurCourant(): Joueur
+PasserLaMain(): void
+GenererCode(): Code
+CommencerLaPartie(): void
+EstTerminee(): bool
+Gagnants(): Joueur[]
+Perdants(): Joueur[]
}
class ReglesClassiques {
-nbJoueurs: int = 0
-joueurCourant: int?
---
+Nom: string = "Règles classiques"
+TourMaximum: int = 12
+TailleCodeMaximum: int = 4
+NbJoueurs: int
+NbJoueursMaximum: int = 2
---
+ReglesClassiques()
}
IRegles <|.. ReglesClassiques
ReglesClassiques *--> Joueur: -joueurs: Joueur[]
class Partie {
---
+StringEventHandler<TEventArgs>(sender: Object?, e: TEventArgs): string?
+JetonEventHandler<TEventArgs>(sender: Object?, e: TEventArgs): Jeton
---
+DemanderJoueur: StringEventHandler<DemanderJoueurEventArgs>?
+DemanderJeton: JetonEventHandler<DemanderJetonEventArgs>?
+AjouterJoueur: EventHandler<AjouterJoueursEventArgs>?
+DebutPartie: EventHandler<AjouterJoueursEventArgs>?
+NouveauTour: EventHandler<AjouterJoueursEventArgs>?
+NouveauJeton: EventHandler<AjouterJoueursEventArgs>?
+NouveauCode: EventHandler<AjouterJoueursEventArgs>?
+PasserMain: EventHandler<AjouterJoueursEventArgs>?
+PartieTerminee: EventHandler<AjouterJoueursEventArgs>?
---
-QuandDemanderJoueur(int numero): string?
-QuandDemanderJeton(): Jeton?
-QuandAjouterJoueur(Joueur joueur): void
-QuandDebutPartie(): void
-QuandNouveauTour(Joueur joueur, int tour, Jeton?[][] grille, Indicateur[][] indicateurs): void
-QuandNouveauJeton(Jeton jeton): void
-QuandNouveauCode(Code: code): void
-QuandPasserMain(): void
-QuandPartieTerminee(Joueur[] gagnants, Joueur[] perdants): void
+Partie(IRegles regles)
+Jouer(): void
}
Partie *--> IRegles: -regles: IRegles
@enduml
Diagramme de paquetage
@startuml
package CoreLibrary <<Rectangle>> {
package Core <<Rectangle>> {
class Code
class Plateau
struct Jeton
enum Couleur
enum Indicateur
}
package Joueurs <<Rectangle>> {
class Joueur
}
package Regles <<Rectangle>> {
interface IRegles
class ReglesClassiques
}
package Events <<Rectangle>> {
class AjouterCodeEventArgs
class AjouterJetonEventArgs
class AjouterJoueurEventArgs
class DebutPartieEventArgs
class DemanderJetonEventArgs
class DemanderJoueurEventArgs
class NouveauTourEventArgs
class PartieTermineeEventArgs
class PasserMainEventArgs
}
package Exceptions <<Rectangle>> {
class CodeCompletException
class CodeIncompletException
class CodeInvalideException
class CodeVideException
class GrilleCompleteException
class IndiceCodeException
class PartieNonCommenceeException
class TailleCodeException
class TailleGrilleException
}
class Partie
}
package ConsoleApp <<Rectangle>> {
class Evenements
class Program
class Utils
}
Program -[dashed]-> Evenements
Program -[dashed]-> Utils
ConsoleApp -[dashed]-> CoreLibrary
Partie -[dashed]-> Events
Partie -[dashed]-> Regles
Partie -[dashed]-> Joueurs
Partie -[dashed]-> Core
Core -[dashed]-> Exceptions
Joueurs -[dashed]-> Exceptions
Regles -[dashed]-> Exceptions
@enduml
Diagramme de séquence
Ajouter un code
Description diagramme de séquence ajouter un code
-
CreerCode(code : Code)
- La partie déclenche la méthode
CreerCode
avec un code vide en paramètre.
- La partie déclenche la méthode
-
DemanderJeton(nbJetons : int)
- La partie demande à l'événement de demander des jetons en spécifiant le nombre de jetons à ajouter.
-
ListeCouleur()
- L'événement envoie une liste de couleurs au joueur.
-
Couleur
- Le joueur sélectionne une couleur pour le jeton.
-
Jeton(couleur : Couleur)
- Le jeton est créé avec la couleur sélectionnée en paramètre.
-
Jeton
- Le jeton est retourné à la partie pour indiquer qu'il a bien été créé.
-
Jeton
- Le jeton choisi est affiché au joueur.
-
AjouterJeton(jeton : Jeton)
- Le jeton est ajouté à la combinaison du joueur courant.
-
Code
- Une fois les 4 jetons ajoutés à la combinaison, celle-ci est retournée à la partie.
-
AjouterCode(code : Code)
- Le code est ajouté au plateau de jeu.
-
ComparerCode(code : Code, codeSecret : Code)
- La combinaison est comparée avec le code secret pour voir s'il y a des jetons de la bonne couleur ou à la bonne place.
-
Indicateur
- Les indicateurs sont retournés au plateau pour y être ajoutés.
-
EstBonCode(code : Code)
- Les indicateurs sont vérifiés pour voir s'il s'agit du code secret.
-
Plateau
- Le plateau retourne l'état actuel avec le code et les indicateurs à la partie.
-
PasserLaMain()
- La partie passe la main au joueur suivant.
-
Joueur Suivant
- Le prochain joueur est retourné à la partie.
Notes
- Boucle TailleCode < 4 : La boucle continue tant que la taille du code est inférieure à 4.
Ce diagramme décrit le processus de création et d'ajout d'un code par le joueur, depuis la demande des couleurs des jetons jusqu'à la comparaison de la combinaison avec le code secret et la notification des résultats.
Ajouter un joueur
Description diagramme de séquence ajouter un un joueur
-
AjouterJoueurs()
- La partie déclenche la méthode
AjouterJoueurs()
.
- La partie déclenche la méthode
-
DemanderJoueur()
- La partie demande à l'événement de demander un joueur.
-
Demande le nom
- L'événement demande au joueur de saisir son nom.
-
Nom
- Le joueur fournit son nom.
-
Nom
- L'événement retourne le nom du joueur.
-
AjouterJoueur(nom : string)
- La partie appelle la méthode
AjouterJoueur
avec le nom du joueur en paramètre pour l’ajouter à la partie.
- La partie appelle la méthode
-
Joueur(nom : string, Plateau (TailleCodeMax : int, NbTourMax : int))
- La partie crée un nouvel objet
Joueur
avec le nom et un nouveau plateau.
- La partie crée un nouvel objet
-
Plateau(TailleCodeMax : int, NbTourMax : int)
- Le joueur crée un plateau avec la taille maximale du code et le nombre maximal de tours.
-
GenererCodeAleatoire()
- Le plateau génère un code aléatoire. C’est le code secret du joueur
-
AjouterJeton(RandomCouleur : Couleur)
- Le plateau ajoute au code secret un jeton avec une couleur aléatoire.
-
Jeton
- Le jeton est créé et retourné au plateau.
-
Plateau
- Le plateau est retourné.
-
Joueur
- Le joueur est retourné aux règles.
-
Joueur
- La partie reçoit le joueur ajouté.
Notes
- Boucle NombreJoueur < 2 : La boucle continue tant que le nombre de joueurs est inférieur à 2.
- Boucle TailleCode < 4 : La boucle continue tant que la taille du code est inférieure à 4.
Ce diagramme décrit le processus d'ajout d'un joueur à la partie, depuis la demande du nom jusqu'à la création complète du joueur et son plateau de jeu.
Partie terminée
Description diagramme de séquence partie terminée
-
estTerminee()
- La class Partie appelle la méthode pour savoir si la partie est terminée
-
Retourner le statut de fin de partie
- La classe
Règles
retourneVrai
si les conditions de fin de partie sont remplies (joueur courant a plus de 12 tours ou victoire est vraie).
- La classe
-
Gagnant() -La liste des gagnants est créée avec les joueurs.
-
Retourner la liste des gagnants
- La liste des gagnants est retournée .
-
Perdant()
- La liste des perdants est créée avec les joueurs.
-
Retourner la liste des perdants
- La liste des perdants est retournée.
-
PartieTerminee(Liste Gagnants : Liste, Liste Perdants : Liste)
- La classe
Partie
envoie un message à l'événement pour notifier que la partie est terminée avec les listes de gagnants et de perdants (PartieTerminee(Liste Gagnants : Liste, Liste Perdants : Liste)
).
- La classe
-
Affichage du résultat - Égalité (Égalité)
- Si le nombre de gagnants est supérieur à 1 (
Gagnant > 1
), l'événement affiche Égalité
- Si le nombre de gagnants est supérieur à 1 (
-
)Affichage du résultat - Gagnant unique (Nom gagnant)
- Si le nombre de gagnants est égal à 1 (
Gagnant == 1
), affiche le nom du gagnant (Nom gagnant
).
- Si le nombre de gagnants est égal à 1 (
-
Affichage du résultat - Défaite (Défaite)
- Si le nombre de gagnants est égal à 0 (
Gagnant == 0
), l'événement affiche une défaite (Défaite
).
- Si le nombre de gagnants est égal à 0 (
-
Partie non terminée (False)
- Si la partie n'est pas terminée, la classe
Règles
retourneFalse
.
- Si la partie n'est pas terminée, la classe
-
Initier un nouveau tour (NouveauTour)
- La classe
Partie
appelle la méthodeNouveauTour
sur l'événement avec les paramètres du joueur courant, du tour, du plateau et de l'indicateur (NouveauTour(joueurCourant : Joueur, Tour : int, plateau : Plateau, indicateur : Indicateur)
).
- La classe
-
Afficher le nouveau tour
- L'événement affiche les informations sur le nom du joueur, le plateau, l'indicateur et le tour (
Nom, Plateau, Indicateur, Tour
).
- L'événement affiche les informations sur le nom du joueur, le plateau, l'indicateur et le tour (
Notes
- Conditions : Les conditions sont vérifiées pour décider si la partie est terminée ou si un nouveau tour doit être initié.
- Résultats : Les résultats sont affichés en fonction du nombre de gagnants.
- Nouveau Tour : Si la partie n'est pas terminée, un nouveau tour est initié pour le joueur courant.
Description de l'architecture
La classe Partie
La classe Partie
est le point central de notre application, orchestrant les différentes phases du jeu. Partie
est une classe, car elle centralise la logique de contrôle du jeu. Une classe permet de regrouper les méthodes et les événements nécessaires pour orchestrer les différentes phases du jeu.
Afin de jouer une partie facilement, une partie a besoin des règles choisies. Il suffit alors d'écouter les événements et de démarrer la partie.
La classe va alors faire tout le déroulement d’une partie grâce aux règles et elle va notifier son avancement au travers des événements. Plusieurs gestionnaires d'événements (EventHandler) sont définis pour différentes actions comme demander un joueur, débuter une partie, ajouter un joueur, commencer un nouveau tour, etc.
Les méthodes QuandDemanderJoueur
, QuandAjouterJoueur
, QuandDebutPartie
, etc., permettent de définir le comportement du jeu à différentes étapes. Ces méthodes sont conçues pour être appelées lors des événements correspondants.
L'interface IRegles
Afin de pouvoir jouer aux différents modes de notre jeu, il existe l’interface IRegles
. Cette interface nous donne des informations importantes sur la partie.
Il y a le nom, le nombre de tours maximum, le nombre de joueurs possibles, la taille d'un code. Mais également le joueur actuel, son plateau, et la possibilité de générer un code vide, définissent les paramètres essentiels des règles du jeu.
Enfin, elle permet de connaître l'état de la partie, les gagnants et/ou les perdants.
L'interface IRegles
définit donc les propriétés et les méthodes que toute règle de jeu doit implémenter.
La classe ReglesClassiques
Elle implémente IRegles
. Ainsi, elle permet de jouer à une version classique du Mastermind. Deux joueurs s'affrontent au cours de douze tours pour essayer de trouver en premier le code à quatre couleurs.
Les attributs nbJoueurs
et joueurCourant
permettent de suivre l'état de la partie.
La classe Joueur
Elle représente un joueur dans le jeu. Joueur
est une classe, car elle nous permet d'encapsuler les données propres à chaque joueur et les comportements associés. Cela facilite la gestion de l'état et des actions de chaque joueur de manière isolée.
Un joueur possède un nom et un plateau. À l’appel du constructeur, on fournit le nom du joueur et son plateau de jeu associé. Ils ne pourront pas être modifiés.
La classe Plateau
Elle gère l'état du plateau de jeu d’un joueur. Plateau
est une classe, car c’est idéale pour encapsuler la logique complexe de manipulation des jetons, de vérification des codes, et de gestion de l'état de la partie pour un joueur.
À la construction, le plateau a besoin d'une taille pour la grille et de la taille de ses codes. Les propriétés tailleCode
, Victoire
et Tour
indiquent l'état actuel du plateau.
De plus, il génère un code aléatoire qui lui est personnel et qu'il gardera tout au long de son existence. Il est ensuite possible de lui insérer un code complet qu'il ajoute dans un tableau. Lorsque ce code est inséré, il vérifie si ce dernier est le code secret, et génère les indicateurs de bonne couleur et de bonne place, qu'il ajoute aussi dans un tableau.
Il est possible d'obtenir ces deux tableaux afin de connaître les codes déjà joués et les résultats des tours précédents.
La classe Code
Elle représente une séquence de jetons, qui est le code que les joueurs souhaitent essayer.
Un code possède une taille qui doit être respectée. Il est possible de lui ajouter un jeton ou de supprimer le dernier jeton ajouté. Il est aussi possible d'obtenir un ou tous les jetons et de savoir si le code est complet ou non.
Enfin, l’une des méthodes permet de comparer le code entré par le joueur et son code secret, ce qui permet de renvoyer les indicateurs nécessaires au joueur pour trouver son code secret.
La structure Jeton
La structure Jeton
représente un jeton avec une couleur spécifique. La couleur du jeton est accessible mais pas modifiable.
L'énumération Indicateur
Indicateur
est une énumération qui possède deux valeurs : BONNE_COULEUR
et BONNE_PLACE
. C’est une énumération, car elle représente un ensemble fixe de valeurs possibles.
Si le code couleur proposé par l’un des joueurs possède un jeton de la bonne couleur, mais à la mauvaise place, un indicateur BONNE_COULEUR
sera donné. Si le code possède un jeton de la bonne couleur et à la bonne place, un indicateur BONNE_PLACE
sera donné. Nous avons choisi une énumération pour cette structure, car les énumérations offrent des noms symboliques significatifs, ce qui rend le code plus lisible et moins sujet aux erreurs.
L'énumération Couleur
Couleur
contient toutes les couleurs possibles que peut prendre un jeton. C’est également une énumération tout comme Indicateur
, car elle représente un ensemble fini de couleurs possibles pour les jetons.
On y retrouve le rouge, le vert, le bleu, le jaune, le noir et le blanc. Tout comme l’énumération Indicateur
, nous avons choisi une énumération, car il s’agit d’une structure simple et que les noms symboliques rendent le code plus lisible et est moins sujet aux erreurs.
Interaction entre les classes
-
La classe
Partie
:- Interaction avec l'interface
Règles
:- Initialise et démarre la partie en appelant les méthodes appropriées de la classe
Règles
. - Utilise la classe
Règles
pour vérifier l'état du jeu, notamment pour savoir si la partie est terminée. - Appelle la classe
Règles
pour gérer le passage de tour entre les joueurs.
- Initialise et démarre la partie en appelant les méthodes appropriées de la classe
- Interaction avec la classe
Plateau
:- Ajoute les combinaisons proposées par les joueurs au plateau de jeu en utilisant les méthodes de la classe
Plateau
. - Met à jour le plateau de jeu après chaque tour.
- Ajoute les combinaisons proposées par les joueurs au plateau de jeu en utilisant les méthodes de la classe
- Interaction avec les joueurs :
- Informe les joueurs de l'état du jeu, des tours en cours et des résultats des combinaisons.
- Interaction avec l'interface
-
La classe
Plateau
:- Interaction avec la classe
Code
:- Récupère les codes secrets et les indicateurs de résultats pour chaque combinaison proposée.
- Met à jour la grille de jetons sur le plateau en fonction des résultats obtenus.
- Interaction avec la classe
-
La classe
Code
:- Interaction avec la classe
Jeton
:- Ajoute des jetons de couleur à la combinaison en cours, en utilisant la classe
Jeton
. - Génère et valide les codes secrets et les combinaisons proposées par les joueurs.
- Ajoute des jetons de couleur à la combinaison en cours, en utilisant la classe
- Validation et feedback :
- Compare les combinaisons proposées aux codes secrets et génère les indicateurs en conséquence
- Interaction avec la classe
Évènements
Nous avons plusieurs événements qui sont appelés tout au long de la partie pour afficher ou permettre au joueur d'entrer des informations :
- Saisie du nom du joueur : Demande au joueur de saisir son nom.
- Affichage des informations du joueur en cours : Affiche le nom, le tour et le plateau du joueur en cours.
- Choix des couleurs des jetons : Demande aux joueurs de choisir les couleurs de leurs jetons pour créer une combinaison.
- Affichage des résultats de la partie : Affiche les joueurs gagnants, perdants ou une égalité en cas de fin de partie.
Exceptions
Nous avons plusieurs exceptions pour gérer les différents problèmes qui pourraient survenir :
- Suppression de jeton sur combinaison vide : Empêche la suppression d'un jeton lorsque la combinaison du joueur est vide.
- Validation des combinaisons : Assure que les combinaisons des joueurs sont complètes et ne dépassent pas leur taille maximale.
- Ajout de combinaison avant le début de la partie : Empêche l'ajout d'une combinaison lorsque la partie n'a pas encore commencé.
- Ajout de combinaison sur plateau complet : Empêche l'ajout d'une combinaison si le plateau est déjà complet.
Chaque classe a une responsabilité clairement définie. Plateau gère l'état du plateau, tandis que la classe Code gère la logique des codes.
Table of Contents
- Mastermind
- Conception de l'application
- Diagramme de classes
- Diagramme de paquetage
- Diagramme de séquence
- Ajouter un code
- Notes
- Ajouter un joueur
- Description diagramme de séquence ajouter un un joueur
- Notes
- Partie terminée
- Description diagramme de séquence partie terminée
- Notes
- Description de l'architecture
- La classe Partie
- L'interface IRegles
- La classe ReglesClassiques
- La classe Joueur
- La classe Plateau
- La classe Code
- La structure Jeton
- L'énumération Indicateur
- L'énumération Couleur
- Interaction entre les classes
- Évènements
- Exceptions