/*

   _                .-.   
  :_;               : :   
  .-. .--. .-..-.   : `-. 
  : :' '_.': :; : _ : .. :
  : :`.__.'`.__.':_;:_;:_;
.-. :                     
`._.'                     


FICHIER	: jeu.h
DATE	: Fevrier 2003
AUTEUR	: Aymeric
EMAIL	: Aymeric.Demartin@iup.univ-avignon.fr
GROUPE	: IUP1 GMI Avignon - Groupe 5 (RT)

*/


#ifndef JEU_H
#define JEU_H

#include "global.h"
#include "joueur.h"
#include "labyrinthe.h"

class Jeu {
	private :
		Joueur listejoueur[5];
		int numero_courant;
		int nombre_partie;
	public :
                Jeu(int, int);
		~Jeu();
                int rentreTaille();
                int rentreDensite();
                void rentreNombrePartie();
                void affiche_commandes(int);
		void joueur_suivant(int&, int, int);
                void jouePartie(int, bool);
};



/*------------
  CONSTRUCTEUR
  ------------*/
Jeu::Jeu(int nbj, int nbpartie)
{
	numero_courant=1;
	nombre_partie=nbpartie;
}

/*-----------
  DESTRUCTEUR
  -----------*/
Jeu::~Jeu()
{
	delete []listejoueur;
}


/*----------
  ACCESSEURS
  ----------*/
  
// on rentre la taille du labyrinthe
int Jeu::rentreTaille()
{
	int max=0;
	while ((max < 15) || (max > 30))
	{
		printw("\nRentrez la taille du labyrinthe (entre 15 et 30) : ");
		scanw("%d",&max);
	}
	return(max);
}

// on rentre la densite du labyrinthe
int Jeu::rentreDensite()
{
	int densite=0;
	while ((densite < 60) || (densite > 100))
	{
		printw("\nRentrez la densite du labyrinthe (%% de case vide) (entre 60 et 100) : ");
		scanw("%d",&densite);
	}
	return(densite);
}

// on rentre le Nombre de parties a jouer
void Jeu::rentreNombrePartie()
{
	printw("\nRentrez le nombre de parties que vous voulez jouer : ");
	scanw("%d",&nombre_partie);
}


/*---------
  FONCTIONS
  ---------*/

// permet l'affichage des commandes a l'ecran
void Jeu::affiche_commandes(int max)
{
	move(max+3,0);
	printw("'a' pour se deplacer vers le haut\n");
	printw("'q' pour se deplacer vers le bas\n");
	printw("'p' pour se deplacer vers la droite\n");
	printw("'o' pour se deplacer vers la gauche\n");
	printw("'i' pour afficher les informations du joueur en cours\n");
	printw("'s' pour afficher le plus court chemin dans la partie en cours\n");
	printw("'x' pour quitter le jeu.\n\n\n\n");
	move(max+1,0);
}

// fonction permettant de passer au joueur suivant
void Jeu::joueur_suivant(int &num, int num_max, int taille)
{
	if (num < num_max) num++;
	else num=1;
	move(taille+1,0);
	printw("Au joueur numero %d de jouer !",num);
}

// la fonction jouePartie qui lance une partie
void Jeu::jouePartie(int nb, bool encore)
{

	while (encore)
	{
		// fonction pour effacer l'ecran
		clrsrc();

		int verifie=0,x,y,densite,max,i;

		// activation de l'affichage
		echo();

		printw("\n\n\t+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+-+-+\n");
		printw("\t|C|o|n|f|i|g|u|r|a|t|i|o|n| |d|u| |L|a|b|y|r|i|n|t|h|e|\n");
		printw("\t+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+-+-+\n\n");

		// si c'est la premiere partie, on rentre le nombre de partie que l'on veut faire
		if (numero_courant == 1)
		{
			// on rentre le nombre de partie
			rentreNombrePartie();
		}
		else
		{
			printw("\n\t\t+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+\n");
			printw("\t\t|N|o|u|v|e|l|l|e| |p|a|r|t|i|e|\n");
			printw("\t\t+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+\n");
		}

		// on rentre la taille du labyrinthe
		max=rentreTaille();

		// on rentre la densite du labyrinthe
		densite=rentreDensite();

		bool ok=false,impossible=true;
		int nbTentative=0;

		// on definit l'objet labyrinthe en passant en parametre la taille et la densite du labyrinthe
		// on cree donc notre labyrinthe
		Labyrinthe laby(max,densite);

		// tant que le labyrinthe n'est pas correct on recommence
		while (ok == false)
		{
			// on place la cible dans le labyrinthe
			laby.place_cible();

			for (i=1; i <= nb; i++)
			{
				listejoueur[i].calculePositionInitiale(laby,i);
				ok=laby.PlusCourtChemin(listejoueur[i].retournePosition_i_x(),listejoueur[i].retournePosition_i_y(),laby.RetournePositionCible().x,laby.RetournePositionCible().y,false,nb);
				if (ok == false)
				{	
					laby.remplideVide();
					laby.faitLesMurs();
					laby.GenereBlocs(nbTentative);
					break;
				}
			}

			nbTentative++;
			
			// si on a atteint 100 tentatives, on demande de rentrer de nouvelles donnees
			if (nbTentative > 100)
			{
				clrsrc();
				printw("\n\n\t+-+-+-+-+-+-+-+-+-+\n");
				printw("\t|A|T|T|E|N|T|I|O|N|\n");
				printw("\t+-+-+-+-+-+-+-+-+-+\n\n");
				printw("=> Impossible de creer le labyrinthe avec la configuration actuelle\n");
				printw("\n... Appuyez sur une touche pour continuer ...\n");
				getch();
				impossible=false;
				numero_courant--;
				break;
			}

		}

		// on initialise le numero du joueur qui commence aleatoirement
		srand(getpid());
		int numero=(rand() % nb) + 1;

		int ax, bx, ay, by;

		// on complete l'objet joueur
		for (i=1; i <= nb; i++)
		{
			x=listejoueur[i].retournePosition_i_x();
			y=listejoueur[i].retournePosition_i_y();
			listejoueur[i].setId(i);
			listejoueur[i].setPosition_c(x,y);
			listejoueur[i].setDeplacement(0);
			laby.PlaceJoueur(x,y,i);
		}

		// on efface l'ecran
		clrsrc();

		// on affiche le labyrinthe
		laby.affiche_labyrinthe(1);
		refresh();

		// debut de la partie
		move(max+1,0);
		printw("Au joueur numero %d de commencer !",numero);

		// affichage des commandes
		affiche_commandes(max);

		// on desactive l'echo, donc quand on tape sur une touche, on ne voit pas ce qu'on tape
		// comme dans un vrai jeu
		noecho();

		ok=impossible;

		while (ok)
		{
			switch (getch())
			{
			// la commande 'p' permet de se deplacer sur la droite
			case 'p':
				move(max,0);
				printw("\n");
				move(max+1,0);
				printw("\n");
				x=listejoueur[numero].retournePosition_c_x();
				y=listejoueur[numero].retournePosition_c_y()+1;
				// on verifie si on peut aller sur la prochaine case
				verifie=laby.verifie_prochaine_case(x,y);

				// si la prochaine case est libre
				if (verifie == 1)
				{
					// on bouge le joueur et on modifie ses infos
					laby.bouge_joueur(numero,x,y-1,x,y);
					laby.PlaceJoueur(x,y,numero);
					move(0,0);
					laby.affiche_labyrinthe(1);
					refresh();
					listejoueur[numero].incNbdeplacement();
					listejoueur[numero].setPosition_c(x,y);

					// on passe au joueur suivant
					joueur_suivant(numero,nb,max);
				}
				// si la prochaine case est un obstacle
				else if (verifie == 0)
				{
					// on incremente le nombre de deplacement du joueur
					listejoueur[numero].incNbdeplacement();
					move(max,0);
					printw("Vous ne pouvez pas aller ici !\n");

					// on passe au joueur suivant
					joueur_suivant(numero,nb,max);
				}
				// si la prochaine case est la cible
				else
				{
					move(max+1,0);
					// le joueur a gagne, fin de la premiere partie
					printw("LE JOUEUR %d A GAGNE AVEC %d DEPLACEMENTS !\n",listejoueur[numero].retourneId(),listejoueur[numero].retourneNbdeplacement());
					listejoueur[numero].incScore();
					for (i=1; i <= nb; i++)
					{
						printw("\nScore du joueur %d : %d",i,listejoueur[i].retourneScore());
					}
					printw("\n... Appuyez sur une touche pour continuer ...");
					printw("\n\n\n\n\n\n\n");
					getch();
					ok=false;
				}
				move(max+1,0);
				refresh();
				break;
			// la commande 'o' permet de se deplacer sur la gauche
			// idem que precedemment
			case 'o':
				move(max,0);
				printw("\n");
				move(max+1,0);
				printw("\n");
				x=listejoueur[numero].retournePosition_c_x();
				y=listejoueur[numero].retournePosition_c_y()-1;
				verifie=laby.verifie_prochaine_case(x,y);
				if (verifie == 1)
				{
					laby.bouge_joueur(numero,x,y+1,x,y);
					laby.PlaceJoueur(x,y,numero);
					move(0,0);
					laby.affiche_labyrinthe(1);
					refresh();
					listejoueur[numero].incNbdeplacement();
					listejoueur[numero].setPosition_c(x,y);
					joueur_suivant(numero,nb,max);
				}
				else if (verifie == 0)
				{
					move(max,0);
					printw("Vous ne pouvez pas aller ici !\n");
					joueur_suivant(numero,nb,max);
				}
				else
				{
					move(max+1,0);
					printw("LE JOUEUR %d A GAGNE AVEC %d DEPLACEMENTS !",listejoueur[numero].retourneId(),listejoueur[numero].retourneNbdeplacement());
					listejoueur[numero].incScore();
					for (i=1; i <= nb; i++)
					{
						printw("\nScore du joueur %d : %d",i,listejoueur[i].retourneScore());
					}
					printw("\n... Appuyez sur une touche pour continuer ...");
					printw("\n\n\n\n\n\n\n");
					getch();
					ok=false;
				}
				move(max+1,0);
				refresh();
				break;
			// la commande 'a' permet de se deplacer vers le haut
			// idem que precedemment
			case 'a':
				move(max,0);
				printw("\n");
				move(max+1,0);
				printw("\n");
				x=listejoueur[numero].retournePosition_c_x()-1;
				y=listejoueur[numero].retournePosition_c_y();
				verifie=laby.verifie_prochaine_case(x,y);
				if (verifie == 1)
				{
				laby.bouge_joueur(numero,x+1,y,x,y);
					laby.PlaceJoueur(x,y,numero);
					move(0,0);
					laby.affiche_labyrinthe(1);
					refresh();
					listejoueur[numero].incNbdeplacement();
					listejoueur[numero].setPosition_c(x,y);
					joueur_suivant(numero,nb,max);
				}
				else if (verifie == 0)
				{
					move(max,0);
					printw("Vous ne pouvez pas aller ici !\n");
					joueur_suivant(numero,nb,max);
				}
				else
				{
					move(max+1,0);
					printw("LE JOUEUR %d A GAGNE AVEC %d DEPLACEMENTS !",listejoueur[numero].retourneId(),listejoueur[numero].retourneNbdeplacement());
					listejoueur[numero].incScore();
					for (i=1; i <= nb; i++)
					{
						printw("\nScore du joueur %d : %d",i,listejoueur[i].retourneScore());
					}
					printw("\n... Appuyez sur une touche pour continuer ...");
					printw("\n\n\n\n\n\n\n");
					getch();
					ok=false;
				}
				move(max+1,0);
				refresh();
				break;
			// la commande 'q' permet de se deplacer vers le bas
			// idem que precedemment
			case 'q':
				move(max,0);
				printw("\n");
				move(max+1,0);
				printw("\n");
				x=listejoueur[numero].retournePosition_c_x()+1;
				y=listejoueur[numero].retournePosition_c_y();
				verifie=laby.verifie_prochaine_case(x,y);
				if (verifie == 1)
				{
					laby.bouge_joueur(numero,x-1,y,x,y);
					laby.PlaceJoueur(x,y,numero);
					move(0,0);
					laby.affiche_labyrinthe(1);
					refresh();
					listejoueur[numero].incNbdeplacement();
					listejoueur[numero].setPosition_c(x,y);
					joueur_suivant(numero,nb,max);
				}
				else if (verifie == 0)
				{
					move(max,0);
					printw("Vous ne pouvez pas aller ici !\n");
					joueur_suivant(numero,nb,max);
				}
				else
				{
					move(max+1,0);
					printw("LE JOUEUR %d A GAGNE AVEC %d DEPLACEMENTS !",listejoueur[numero].retourneId(),listejoueur[numero].retourneNbdeplacement());
					listejoueur[numero].incScore();
					for (i=1; i <= nb; i++)
					{
						printw("\nScore du joueur %d : %d",i,listejoueur[i].retourneScore());
					}
					printw("\n... Appuyez sur une touche pour continuer ...");
					printw("\n\n\n\n\n\n\n");
					getch();
					ok=false;
				}
				move(max+1,0);
				refresh();
				break;
			// la commande 'i' permet d'afficher des informations sur le joueur en cours
			case 'i':
				listejoueur[numero].affiche_info_joueur(max+3,0,numero_courant,nombre_partie);
				printw("\nAppuyer sur un touche pour continuer la partie ..");
				getch();
				affiche_commandes(max);
				break;
			// la commande 's' permet d'afficher le chemin le plus court
			case 's':
				for (i=1; i <= nb; i++)
				{
					ax=listejoueur[i].retournePosition_c_x();
					ay=listejoueur[i].retournePosition_c_y();
					bx=laby.RetournePositionCible().x;
					by=laby.RetournePositionCible().y;
					laby.PlusCourtChemin(ax,ay,bx,by,true,i);
				}
				move(max+1,0);
				printw("\n");
				move(max+1,0);
				printw("\nLA PARTIE EST TERMINEE");
				for (i=1; i <= nb; i++)
				{
					printw("\nScore du joueur %d : %d",i,listejoueur[i].retourneScore());
				}
				printw("\n... Appuyez sur une touche pour continuer ...");
				printw("\n\n\n\n\n\n");
				getch();
				ok=false;
				break;
			// la commande 'x' permet de quitter la partie en cours
			case 'x':
				ok=false;
				break;
			default:
				break;
			}	
		}

		// une fois la partie finie, on incremente le numero de la partie courante
		// s'il y a encore des parties a jouer on retourne true, sinon on retourne false
		numero_courant++;
		if (numero_courant <= nombre_partie) encore=true;
		else encore=false;
	}
}

#endif
