using CoreLibrary.Persistance; using CoreLibrary.Core; using CoreLibrary.Evenements; using CoreLibrary.Joueurs; using CoreLibrary.Regles; using System.Runtime.Serialization; using CoreLibrary.Exceptions; namespace CoreLibrary { /// /// Classe représentant une partie. /// [DataContract] public class Partie : IEstPersistant { /// /// Evénement déclenché lorsqu'il faut ajouter un joueur à la partie. /// public event EventHandler? PartieDemanderJoueur; /// /// Evénement déclenché lors du commencement de la partie. /// public event EventHandler? PartieDebutPartie; /// /// Evénement déclenché lorsqu'il faut demander à un joueur de jouer. /// public event EventHandler? PartieDemanderJoueurJouer; /// /// Evénement déclenché lorsqu'un nouveau tour commence. /// public event EventHandler? PartieNouveauTour; /// /// Evénement déclenché lorsqu'on passe la main au joueur suivant. /// public event EventHandler? PartiePasserLaMain; /// /// Evénement déclenché lorsque la partie est terminée. /// public event EventHandler? PartiePartieTerminee; /// /// Méthode pour déclencher l'événement qui demande le joueur. /// /// . private void QuandPartieDemanderJoueur(Joueur joueurDemande) => PartieDemanderJoueur?.Invoke(this, new PartieDemanderJoueurEventArgs(joueurs.Count + 1, joueurDemande)); /// /// Méthode pour déclencher l'événement de début de partie. /// private void QuandPartieDebutPartie() => PartieDebutPartie?.Invoke(this, new PartieDebutPartieEventArgs()); /// /// Méthode pour déclencher l'événement demandant à un joueur de jouer. /// /// Le code à utiliser pour jouer. private void QuandPartieDemanderJoueurJouer(Code code) => PartieDemanderJoueurJouer?.Invoke(this, new PartieDemanderJoueurJouerEventArgs(Tour, Joueurs.ElementAt(courant), plateaux.ElementAt(courant), code, joueurs[Joueurs.ElementAt(courant)])); /// /// Méthode pour déclencher l'événement d'un nouveau tour. /// /// Le code utilisé pour le nouveau tour. private void QuandPartieNouveauTour(Code code) => PartieNouveauTour?.Invoke(this, new PartieNouveauTourEventArgs(Tour, Joueurs.ElementAt(courant), plateaux.ElementAt(courant), code, joueurs[Joueurs.ElementAt(courant)])); /// /// Méthode pour déclencher l'événement de passer la main au joueur suivant. /// private void QuandPartiePasserLaMain() => PartiePasserLaMain?.Invoke(this, new PartiePasserLaMainEventArgs(Joueurs.ElementAt(courant))); /// /// Méthode pour déclencher l'événement de fin de partie. /// /// Liste des noms des joueurs gagnants. /// Liste des noms des joueurs perdants. private void QuandPartiePartieTerminee(IReadOnlyList gagnants, IReadOnlyList perdants) => PartiePartieTerminee?.Invoke(this, new PartiePartieTermineeEventArgs(Tour, gagnants, perdants)); /// /// Dictionnaire des joueurs, avec leur nom et le statut de leur joueur (humain ou robot). /// [DataMember] private readonly Dictionary joueurs = new Dictionary(); /// /// Liste des plateaux de jeu. /// plateaux = new List(); /// /// Indice correspondant au joueur courant. /// [DataMember] private int courant = 0; /// /// Liste des noms des joueurs. /// public IEnumerable Joueurs => joueurs.Keys; /// /// Liste des noms des robots. /// public IEnumerable Robots => joueurs.Where(joueur => !joueur.Value).Select(joueur => joueur.Key); /// /// Indique si la partie est terminée. /// [DataMember] public bool Termine { get; private set; } = false; /// /// Numéro du tour actuel. /// [DataMember] public int Tour { get; private set; } = 0; /// /// Règles utilisées dans la partie. /// [DataMember] public IRegles Regles { get; private init; } /// /// Premier constructeur de la partie. /// /// Les règles de la partie. public Partie(IRegles regles) { Regles = regles; } /// /// Deuxième constructeur de la partie. /// /// La partie à reprendre en cours. public Partie(Partie partie) { joueurs = partie.joueurs; plateaux = partie.plateaux; courant = partie.courant; Tour = partie.Tour; Regles = partie.Regles; partie.PartieDemanderJoueur = null; partie.PartieDebutPartie = null; partie.PartieDemanderJoueurJouer = null; partie.PartieNouveauTour = null; partie.PartiePasserLaMain = null; partie.PartiePartieTerminee = null; foreach (string joueur in Joueurs) (joueurs[joueur] ? new Joueur(joueur) : new Robot(joueur)).JouerPartie(this); } /// /// Lance le déroulement de la partie. /// public void Jouer() { if (joueurs.Count != Regles.NbJoueurs) DemanderJoueur(); else DebutPartie(); } /// /// Demande un joueur. /// private void DemanderJoueur() { Joueur joueurDemande = new Joueur(); joueurDemande.JoueurSeConnecter += JoueurConnecte; QuandPartieDemanderJoueur(joueurDemande); } /// /// Connecte les joueurs à la partie. /// /// La classe qui appelle l'événement, ici Joueur. /// L'instance de l'événement JoueurSeConnecterEventArgs créée par Joueur. private void JoueurConnecte(object? sender, JoueurSeConnecterEventArgs e) { if(Joueurs.Contains(e.Joueur.Nom)) { throw new JoueurDejaPresentException(); } if (e.Joueur.Nom.StartsWith("Robot") && e.Joueur.GetType().Equals(typeof(Joueur))) { throw new NomJoueurInterditException(); } joueurs.Add(e.Joueur.Nom, e.Joueur.GetType().Equals(typeof(Joueur))); plateaux.Add(new Plateau(Regles.TailleCode, Regles.NbTour)); e.Joueur.JouerPartie(this); if (joueurs.Count < Regles.NbJoueurs) { DemanderJoueur(); } else { DebutPartie(); } } /// /// Lance le début de la partie. /// private void DebutPartie() { if (Tour == 0) ++Tour; foreach (Plateau plateau in plateaux) { plateau.PlateauAjouterCode += PlateauAjouterCode; } QuandPartieDebutPartie(); NouveauTour(); } /// /// Passe au tour suivant. /// private void NouveauTour() { Code code = new Code(Regles.TailleCode); QuandPartieDemanderJoueurJouer(code); QuandPartieNouveauTour(code); } /// /// Ajoute un code au plateau. /// /// La classe qui appelle l'événement, ici Plateau. /// L'instance de l'événement PlateauAjouterCodeEventArgs créée par Plateau. private void PlateauAjouterCode(object? sender, PlateauAjouterCodeEventArgs e) { QuandPartiePasserLaMain(); if (courant + 1 == joueurs.Count && (e.Plateau.Complet || plateaux.Any(plateau => plateau.Victoire))) { PartieTerminee(); } else { if (courant + 1 == joueurs.Count) { ++Tour; courant = 0; } else ++courant; NouveauTour(); } } /// /// La partie est terminée. /// private void PartieTerminee() { Termine = true; List gagnants = new List(); List perdants = new List(); for (int i = 0; i < joueurs.Count; ++i) { if (plateaux.ElementAt(i).Victoire) gagnants.Add(Joueurs.ElementAt(i)); else perdants.Add(Joueurs.ElementAt(i)); } QuandPartiePartieTerminee(gagnants, perdants); } } }