using CoreLibrary.Core;
using CoreLibrary.Events;
using CoreLibrary.Joueurs;
using CoreLibrary.Regles;
namespace CoreLibrary
{
///
/// Représente une partie de jeu.
///
public class Partie
{
public IRegles Regles { get; private set; }
private readonly List joueurs = new List();
private readonly List plateaux = new List();
private int? courant;
///
/// Événement déclenché lorsqu'il est nécessaire de d'ajouter un joueur.
///
public event EventHandler? DemanderNom;
///
/// Événement déclenché lorsqu'il est nécessaire d'ajouter un joueur.
///
public event EventHandler? AjouterJoueur;
///
/// Événement déclenché lorsqu'une partie commence.
///
public event EventHandler? DebutPartie;
///
/// Événement déclenché lorsqu'un nouveau tour commence.
///
public event EventHandler? NouveauTour;
///
/// Événement déclenché lorsqu'un code est ajouté.
///
public event EventHandler? AjouterCode;
///
/// Événement déclenché lorsque la main est passée au joueur suivant.
///
public event EventHandler? PasserMain;
///
/// Événement déclenché lorsque la partie est terminée.
///
public event EventHandler? PartieTerminee;
///
/// Méthode pour déclencher l'événement de demande du nom d'un joueur.
///
/// Le numéro du joueur à ajouter
/// La classe dans laquelle le nom doit être défini
private void QuandDemanderNom(int numero, JoueurBuilder joueurBuilder) => DemanderNom?.Invoke(this, new DemanderNomEventArgs(numero, joueurBuilder));
///
/// Méthode pour déclencher l'événement d'ajout d'un joueur.
///
/// Le joueur à ajouter.
private void QuandAjouterJoueur(Joueur joueur) => AjouterJoueur?.Invoke(this, new AjouterJoueurEventArgs(joueur));
///
/// Méthode pour déclencher l'événement du début d'un partie.
///
private void QuandDebutPartie() => DebutPartie?.Invoke(this, new DebutPartieEventArgs());
///
/// Méthode pour déclencher l'événement d'un nouveau tour.
///
/// Le joueur dont c'est le tour.
/// Le numéro du tour.
/// Le code dans lequel il faut ajouter les jetons.
/// La grille de jeu.
/// Les indicateurs de jeu.
private void QuandNouveauTour(Joueur joueur, int tour, Code code, IEnumerable> grille, IEnumerable> indicateurs) => NouveauTour?.Invoke(this, new NouveauTourEventArgs(joueur, tour, code, grille, indicateurs));
///
/// Méthode pour déclencher l'événement d'ajout d'un nouveau code.
///
/// Le code ajouté.
private void QuandAjouterCode(Code code) => AjouterCode?.Invoke(this, new AjouterCodeEventArgs(code));
///
/// Méthode pour déclencher l'événement de passage de la main au joueur suivant.
///
private void QuandPasserMain() => PasserMain?.Invoke(this, new PasserMainEventArgs());
///
/// Méthode pour déclencher l'événement de fin de partie.
///
/// La liste des joueurs gagnants.
/// La liste des joueurs perdants.
private void QuandPartieTerminee(IEnumerable gagnants, IEnumerable perdants) => PartieTerminee?.Invoke(this, new PartieTermineeEventArgs(gagnants, perdants));
///
/// Crée une nouvelle instance de la classe Partie.
///
/// Les règles de la partie.
public Partie(IRegles regles)
{
Regles = regles;
}
///
/// Lance le déroulement de la partie.
///
public void Jouer()
{
JoueurBuilder joueurBuilder = new JoueurBuilder();
joueurBuilder.ConstruireJoueur += Joueur;
QuandDemanderNom(joueurs.Count + 1, joueurBuilder);
}
///
/// Un joueur a saisi son nom
///
private void Joueur(Object? sender, ConstruireJoueurEventArgs e)
{
Joueur joueur = new Joueur(string.IsNullOrEmpty(e.Nom) ? $"Joueur {joueurs.Count + 1}" : e.Nom);
Plateau plateau = new Plateau(Regles.TailleCodeMaximum, Regles.TourMaximum);
joueurs.Add(joueur);
plateaux.Add(plateau);
QuandAjouterJoueur(joueur);
joueur.JouerCode += Tour;
if (joueurs.Count != Regles.NbJoueursMaximum)
{
JoueurBuilder joueurBuilder = new JoueurBuilder();
joueurBuilder.ConstruireJoueur += Joueur;
QuandDemanderNom(joueurs.Count + 1, joueurBuilder);
}
else
{
Commencer();
}
}
///
/// La partie démarre
///
private void Commencer()
{
courant = 0;
Joueur joueurCourant = joueurs[courant.Value];
Plateau plateauCourant = plateaux[courant.Value];
QuandDebutPartie();
QuandNouveauTour(joueurCourant, plateauCourant.Tour, new Code(Regles.TailleCodeMaximum), plateauCourant.Grille(), plateauCourant.Indicateurs());
}
///
/// Un joueur a joué son tour
///
private void Tour(Object? sender, JouerCodeEventArgs e)
{
Plateau plateauCourant = plateaux[courant!.Value];
plateauCourant.AjouterCode(e.Code);
QuandAjouterCode(e.Code);
if (++courant == joueurs.Count)
courant = 0;
QuandPasserMain();
if(courant == 0 && (plateauCourant.Tour > Regles.TourMaximum || plateaux.Where(plateau => plateau.Victoire).Any()))
{
Terminee();
}
else
{
Joueur joueurCourant = joueurs[courant!.Value];
plateauCourant = plateaux[courant!.Value];
QuandNouveauTour(joueurCourant, plateauCourant.Tour, new Code(Regles.TailleCodeMaximum), plateauCourant.Grille(), plateauCourant.Indicateurs());
}
}
///
/// La partie est terminée
///
private void Terminee()
{
List gagnants = new List();
List perdants = new List();
for(int i = 0; i < joueurs.Count; i++)
{
if (plateaux[i].Victoire)
gagnants.Add(joueurs[i]);
else
perdants.Add(joueurs[i]);
}
QuandPartieTerminee(gagnants, perdants);
}
}
}