#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>

// MAX = nombre case max du plateau
#define MAX 100
// NB_NAV = nombre de navires 
#define NB_NAV 5




typedef struct 
{
	int x;
	int y;
}t_case;

typedef struct
{
	t_case premiere_case;
	int sens;
	int taille;
}t_navire;

// Fonction nombre aléatoire
void init_nb_aleatoire()
{
	srandom(time(NULL));
}

// Choisit un nombre entre  et max-1
int nb_aleatoire(int max)
{
	return (random()%max);
}

// Initialisation du plateau tout les cases à 0
void init_plateau(int **plateau,int largeur)
{
	int i,j;
	for(i=largeur-1;i>=0;i--)
		for(j=largeur-1;j>=0;j--)
		plateau[i][j]=0;
}

// Affichage d'un plateau
void aff_plateau(int **plateau,int largeur)
{
	int i,j;
	
	for(i=largeur-1;i>=0;i--)
	{
		printf("%2d|| ",i);  
		for(j=0;j<largeur;j++)
		{
			printf("%2d ",plateau[i][j]);
		}
		printf("\n");
	}
	printf("      - ");
	for(i=1; i<largeur;i++)
		printf(" - ");
	printf("\n");

	printf("      0 ");
	for(i=1; i<largeur;i++)
		printf("%2d ",i);
	printf("\n");

}

// transforme un entier en caractère
// si i = 1 -> c= X (touche)
// si i = 2 -> c= . (à l'eau)
// si i = 3 -> c= C (coule)
char translate_int (int i)
{	
	char c;
	if(i==3)
		c='C';
	else
		if ( i == 0)
			c='.';
		else
			if(i == 1)
				c='X';
			else
				c='O';
	return c;
}

// Affichage de la grille du joueur avec des caractères

void aff_plateau_char(int **plateau,int **grille,int largeur, int * navire)
{
	int i,j;
	for(i=largeur-1;i>=0;i--)
	{
		printf("%2d|| ",i);  
		for(j=0;j<largeur;j++)
		{
			if ((grille[i][j]== 1) && (navire[plateau[i][j]-2] == 0))
				printf("%2c ",translate_int(3));
			else
				printf("%2c ",translate_int(grille[i][j]));
		}
		printf("\n");
	}
	printf("      - ");
	for(i=1; i<largeur;i++)
		printf(" - ");
	printf("\n");

	printf("      0 ");
	for(i=1; i<largeur;i++)
		printf("%2d ",i);
	printf("\n");
}

// Creation des navires utilisateur choisit la taille 
t_navire creer_navire(int taille,int largeur)
{
	t_navire nav;
	nav.premiere_case.x = nb_aleatoire(largeur);
	nav.premiere_case.y = nb_aleatoire(largeur);
	nav.sens = nb_aleatoire(4);
	nav.taille = taille;
	return nav;
}

//Affichage d'un navire
void aff_navire(t_navire nav)
{
	printf("Case de départ (%d,%d)\n",nav.premiere_case.x,nav.premiere_case.y);
	switch( nav.sens)
	{
		case 0 : printf("Sens : haut\n");break;
		case 1 : printf("Sens : droite\n");break;
		case 2 : printf("Sens : bas\n");break;
		case 3 : printf("Sens : gauche\n");break;
		default : printf("Fonction aff_navire : erreur de sens du navire vaut %d",nav.sens);
	}
	printf("Taille : %d\n",nav.taille);
}

// Verification lors du placement que le navire à la place ou ne déborde pas

int est_valide(int** plateau,int largeur, t_navire navire)
{
	int i;
	int ok = 1;
	
	switch( navire.sens)
	{
		// sens: haut (y augmente)
		case 0 : 
				// navire déborde du plateau 
				if (navire.premiere_case.y + (navire.taille -1) >= largeur)
					ok = 0;
				else // navire chevauche un autre
				{
					for (i = navire.premiere_case.y; i<navire.premiere_case.y+ navire.taille;i++)
					{ 
						if (plateau[i][navire.premiere_case.x] != 0)
							ok = 0;
					}
				}
				break;
				
		// sens: droite (x augmente)
		case 1 : 	
				// navire déborde du plateau
				if (navire.premiere_case.x + (navire.taille -1) >= largeur)
					ok = 0;
				else // navire chevauche un autre

					for (i = navire.premiere_case.x; i<navire.premiere_case.x+navire.taille;i++)
					{ 
						if (plateau[navire.premiere_case.y][i] != 0)
							ok = 0;
					}
				break;

		// sens: bas (y diminue)
		case 2 : 	
				// navire déborde du plateau
				if (navire.premiere_case.y -(navire.taille -1) <0)
					ok =0;
				else // navire chevauche un autre

				{
					for (i = navire.premiere_case.y; i> navire.premiere_case.y-navire.taille;i--)
					{ 
						if (plateau[i][navire.premiere_case.x] != 0)
							ok = 0;
					}
				}
				break;
				
		// sens: gauche (x diminue)
		case 3 : 
				// navire déborde du plateau
				if (navire.premiere_case.x -(navire.taille -1) <0)
					ok =0;
				else // navire chevauche un autre

				{
					for (i = navire.premiere_case.x; i>navire.premiere_case.x -navire.taille;i--)
					{ 
						if (plateau[navire.premiere_case.y][i] != 0)
							ok = 0;
					}
				}
				break;
		
		default : printf("Fonction est_valide : erreur de sens du navire vaut %d",navire.sens);
	}

	return ok;
}

// Placement des navires
// plateau[i][j] = 0 si il n'y a pas de navire
// plateau[i][j] = taille_navire si il y a un navire
void mise_a_jour(int **plateau,t_navire navire)
{
	int i;
	switch (navire.sens)
	{
		// sens : haut
		case 0 : 	for (i = navire.premiere_case.y; i<navire.premiere_case.y+ navire.taille;i++)
					plateau[i][navire.premiere_case.x]= navire.taille;
				break;		
		// sens : droite
		case 1 : 	for (i = navire.premiere_case.x; i<navire.premiere_case.x+navire.taille;i++)
					plateau[navire.premiere_case.y][i] = navire.taille;
				break;
		// sens : bas
		case 2 : 	for (i = navire.premiere_case.y; i> navire.premiere_case.y-navire.taille;i--)
					plateau[i][navire.premiere_case.x] = navire.taille;
				break;
		// sens : gauche
		case 3 : 	for (i = navire.premiere_case.x; i>navire.premiere_case.x -navire.taille;i--)
					plateau[navire.premiere_case.y][i] = navire.taille;
				break;
		default : printf("Fonction mise_a_jour : erreur de sens du navire vaut %d",navire.sens);
	}

}
// Creation d'une partie avec NB_NAV navires de 2 à NB_NAV+1 cases
void creer_partie(int **plateau,int taille_p)
{
	int i;
	t_navire n;
	
	for (i=0;i<NB_NAV;i=i+1)
	{
			n = creer_navire(i+2,taille_p);
			while(!est_valide(plateau,taille_p,n))
			{
				n = creer_navire(i+2,taille_p);
			}
			mise_a_jour(plateau,n);
		
	}
}


// Interface joueur
// 1) Demande à l'utilisateur les coordonnées de la case qu'il veut jouer
// 	 si elle a déjà été joué (dans la grille joueur case !=0 on redemande une
//    autre case)
// 2) Met à jour la grille du joueur
// 3) retourne la case choisie par l'utilisateur
t_case question(int **case_jouees, int **plateau,int taille_p)
{
	t_case la_case;
	int deja=0;
// Demande de la case tant qu'elle n'est pas dans le plateau et 
// tant qu'elle a  déjà été jouée
	printf("quel case ?\n");
	do
	{
		do
		{
			printf("y = ");
			scanf("%d",&la_case.y);
			printf("x = ");
			scanf("%d",&la_case.x);
		}while((la_case.x>=taille_p) || (la_case.y>=taille_p) ||(la_case.x<0) || (la_case.y<0));
		// la case déborde
		if (case_jouees[la_case.y][la_case.x]!=0)
		{
			deja = 1;
			printf("Vous avez déjà joué cette case, choisissez en une autre\n");
		}
		else
		{
			deja = 0;
		}
	}while(deja == 1); // la case a déjà ete joue
	
// Mise à jour de la grille
	if(plateau[la_case.y][la_case.x]!=0)
		case_jouees[la_case.y][la_case.x]=	1;
	else
		case_jouees[la_case.y][la_case.x]= -1;
	
	return la_case;
}

// Décremente la taille des bateau et retourne le nombre de cases restantes à
// un bâteau touchés 
int decremente(int * navires, t_case c, int ** plateau)
{
	
	if (navires[plateau[c.y][c.x]-2] == 0)
	{
		return 0;
	}
	else
	{
		navires[plateau[c.y][c.x]-2] --;
		return navires[plateau[c.y][c.x]-2];
	}
}

// Fonction qui affiche le résultat du tir
// selon la case joué par l'utilisateur 
// - OUT : si sort du plateau 
// - TOUCHE si bateau touche et dans se cas décremente le nb de case restante
// dans le tableau navire
// - COULE si le bateau touche et si la case correspondnate dans navire est
// égale à 0
// A l'EAU sinon
void reponse(t_case la_case, int **plateau, int largeur, int * navire)
{
	if ((la_case.y >= largeur)||(la_case.x >= largeur))
	{
		printf(">>>>>>>>> OUT <<<<<<<<<\n");
	}
	else
	{
		if (plateau[la_case.y][la_case.x] != 0)
		{
			if (decremente (navire, la_case,plateau) == 0)
				printf(">>>>>>>>> COULE  navire de %d cases<<<<<<<<<\n",plateau[la_case.y][la_case.x]);
			else
				printf(">>>>>>>>> TOUCHE <<<<<<<<<\n");
		}
		else printf (">>>>>>>>> A L'EAU <<<<<<<<<\n");
	}
}


// Retourne 1 si toutes les cases du plateau où il y a un navire on une case
// correspondante dans la grille du joueur dans laquelle il y a un 1.
// Retourne 0 si pour au moins une case du plateau où il ya un navire la case
// correspondante dans le grille n'a pas encore été joué.
int gagne(int **p1,int **p2,int largeur)
{
	int i, j;
	int ok = 1;
	for (i=0;i<largeur;i++)
		for(j=0;j<largeur;j++)
		{
			if ((p1[i][j] != 0) && (p2[i][j] == 0))
				ok =0;
		}
	return ok;
		
}


int main()
{

	int i, rsp;
	int taille_p;
	// plateaux de jeu
	int **grille;
	int **plateau;
	/* tableau des navires contenant leur tailles (1 navire par taille entre 2 et NB_NAV)*/
	int * navires;

	//compteur des coups joués
	int compteur = 0;

	
	// Initialisation du random
	init_nb_aleatoire();

	// Définir la taille du jeu
	do
	{
		printf("Taille du plateau (MIN 7 ; MAX 100)?\n" );
		scanf("%d",&taille_p);
	}while((taille_p<6) || (taille_p >=100));
	
	// Initialisation dynamique des plateaux de jeu
	plateau = (int **)malloc(sizeof(int*)*taille_p);
	for(i=0;i<taille_p;i=i+1)
	{
		plateau[i]=(int*)malloc(sizeof(int)*taille_p);
	}
	grille = (int **)malloc(sizeof(int*)*taille_p);
	for(i=0;i<taille_p;i=i+1)
	{
		grille[i]=(int*)malloc(sizeof(int)*taille_p);
	}

	navires =(int*)malloc(sizeof(int)*NB_NAV);

	// Initialisation des plateaux avec des 0 parout
	init_plateau( plateau,taille_p);
	init_plateau( grille,taille_p);

	// Initialisations du tableau des navires avec la taille de chaque navire
	for(i=0;i<NB_NAV;i=i+1)
	{
		navires[i]=i+2;
	}
	

		
	// Lancer la partie
	//Création du plateau avec les navires
	creer_partie(plateau,taille_p);
	
	// aff_plateau(plateau,taille_p); // Afficher la solution
	
	//Tant que l'on a pas gagné, on continue !
	
	while(gagne(plateau,grille,taille_p)==0)
	{
		compteur = compteur+1; // augmente le nombre de coup joué
		reponse(question(grille,plateau,taille_p),plateau,taille_p,navires);
		printf("Voullez vous visualiser les cases déjà joués ? (non = 0/ oui = 1)\n");
		scanf("%d",&rsp);
		if (rsp == 1)
			aff_plateau_char(plateau,grille,taille_p,navires);
	}
	
	printf("\n\n *****************************\n");
	printf("              BRAVO\n"); 
	printf("  Vous avez gagné en %d coups\n",compteur);
	printf(" *****************************\n\n\n");
	
	
	// Liberation des pointeurs
	free(navires);
	free(plateau);
	free(grille);
	return 1;
}
