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

/* Pour la variable type_game, on utilise les macros GAME_IA et GAME_MULTI
 * commes valeurs (qui remplacent 1 et 2).
 */
#define GAME_IA 1
#define GAME_MULTI 2

/* On identifie les deux joueurs par 1 et 2, et pour que ça soit plus
 * lisible, on remplace 1 et 2 par FIRST_PLAYER et SECOND_PLAYER
 * dans le code.
 */
#define FIRST_PLAYER 1
#define SECOND_PLAYER 2

int type_game = 0; // cette variable contient le type du jeu, soit contre une IA (GAME_IA), soit deux joueurs (GAME_MULTI)
int to_play = 0; // cette variable contient le numero du joueur à qui c'est de jouer
/* Le tableau morpion est rempli de 0 à l'origine, et lorsqu'un joueur
 * y met une marque sur une case, celle-ci a comme valeur le numero
 * de ce joueur.
 */
static int morpion[3][3]; // static initialise le tableau à 0

/* Cette fonction permet de retourner si il y a un gagnant (1) ou pas (0).
 * Elle vérifie les colones, les lignes et les diagonales.
 */
int is_there_winner()
{
        int i,j;
        /* ligne permet de compter, pour chaque lignes, le nombre de fois que le joueur de la première case
         * mis une marque. Si donc ligne == 3 à la fin de l'étude de la ligne, c'est qu'il a alligné
         * On fait la même chose en colone avec la variable colone.
         */
        int ligne, colone;
        for(i = 0; i < 3; ++i)
        {
                ligne = colone = 0;
                for(j = 0; j < 3; ++j)
                {
                        // On prends la colone i, et on vérifie pour chaques lignes 0, 1 et 2 avec j
                        if(morpion[j][i] != 0 && (!j || morpion[j][i] == morpion[j-1][i]))
                                colone++;
                        // On prends la ligne i, et on vérifie pour chaques colone 0, 1 et 2 avec j
			if(morpion[i][j] != 0 && (!j || morpion[i][j] == morpion[i][j-1]))
				ligne++;
		}
		/* Si sur la ligne i étudiée il y a 3 marques du même joueur,
		 * ou si sur la colone i étudiée il y a 3 marques du même joueur,
		 * il y a un gagnant.
		 */
		if(ligne == 3 || colone == 3)
			return 1;
	}
	/* Si la case du milieu a un propriétaire,
	 * on vérifie si c'est le même pour les cases en haut à gauche et en bas à droite,
	 * ou si c'est le même pour les cases en haut à droite et en bas à gauche.
	 */
	if(morpion[1][1] != 0 &&
	   (morpion[0][0] == morpion[1][1] && morpion[2][2] == morpion[1][1] ||
	    morpion[2][0] == morpion[1][1] && morpion[0][2] == morpion[1][1]))
		return 1;

	/* Si jusque là on a pas trouvé de lignes, colones ou diagonales remplies par un seul joueur,
	 * on retourne 0 pour indiquer qu'il n'y a pas de gagnant.
	 */
	return 0;
}

/* Cette fonction renvoie 1 si le jeu est terminé */
int is_end()
{
	int i,j;
	
	/* On appelle d'abord la fonction is_there_winner(), pour vérifier
	 * si quelqu'un n'a pas déjà gagné.
	 */
	if(is_there_winner())
		return 1;

	/* Si personne n'a gagné, on va vérifier si toutes les cases ne sont pas remplies (dans ce cas là il y a match nul */
	for(i = 0; i < 3; ++i)
		for(j = 0; j < 3; ++j)
			if(morpion[i][j] == 0)
				return 0;
	return 1;
}

/* Cette fonction affiche l'etat du morpion. */
void display_morpion()
{
	int i,j;
	for(i = 0; i < 3; ++i)
	{
		printf("-------\n");
		printf("|");
		for(j = 0; j < 3; ++j)
		{
			int c = morpion[i][j];
			printf("%c|", c == FIRST_PLAYER ? 'X' : c == SECOND_PLAYER ? 'O' : ' ');
		}
		printf("\n");
	}
	printf("-------\n");
}

/* Cette fonction fait jouer l'intelligence artificielle.
 * Elle ne fait que jouer sur la première case libre qu'elle trouve.
 */
void ia_play()
{
	int i,j;
	for(i = 0; i < 3; ++i)
		for(j = 0; j < 3; ++j)
			if(morpion[i][j] == 0)
			{
				morpion[i][j] = to_play;
				printf("\n[[ L'intelligence Artificielle a joué ]]\n");
				return;
			}
}

/* Cette fonction demande au joueur suivant de jouer. */
void ask_to_play()
{
	int x = 0, y = 0;
	
	/* Si c'est une partie avec un joueur artificielle et si c'est au second joueur de jouer (donc l'IA),
	 * alors on appelle ia_play().
	 */
	if(type_game == GAME_IA && to_play == SECOND_PLAYER)
	{
		ia_play();
		return;
	}

	printf("\n[[ Joueur %d à vous de jouer ! ]]\n", to_play);
	printf("Veuillez entrer les coordonnées de la case (sous forme \"x,y\") où vous souhaitez poser votre %s :\n", to_play == FIRST_PLAYER ? "croix" : "rond");
	
	/* On utilise uen boucle infinie tant qu'on a pas reçu une valeur correcte */
	while(1)
	{
		printf("> ");
		scanf("%d,%d", &x, &y); // On récupère le couple x,y
	
		/* Si x n'est pas compris entre 1 et 3 ou si y n'est pas compris entre 1 et 3, on renvoie une erreur et la boucle continue pour redemander */
		if(x < 1 || x > 3 || y < 1 || y > 3)
			printf("\nErreur ! Les nombres doivent être compris entre 1 et 3 et être écrits sous la forme \"x,y\"\n");
		else if(morpion[y-1][x-1] > 0) // Si la valeur de la case est supérieur à 0, c'est que quelqu'un a déjà marqué cette case
			printf("\nErreur ! La case %d,%d a déjà été marquée par %s !\n", x, y, morpion[y-1][x-1] == to_play ? "vous" : "l'autre joueur");
		else // Il n'y a pas d'erreur, donc on sort de la boucle
			break;
	}
	// On transforme en indexage tableau (de [1..3], on passe à [0..2])
	y--;
	x--;
	
	morpion[y][x] = to_play; // On inscrit dans la case le numero du player qui joue
}

int main()
{
	printf("\nBienvenue dans le morpion.\n\n");
	printf("Entrez le nombre du type de jeu que vous souhaitez faire :\n");
	printf("[1] Jeu seul contre une Intelligence Artificielle\n");
	printf("[2] Jeu à deux\n\n");
	
	/* Tant qu'on a pas reçu 1 ou 2, on continue à demander */
	do
	{
		printf("> ");
		scanf("%d\n", &type_game);
	} while (type_game != GAME_IA && type_game != GAME_MULTI);
	
	/* Affichage du morpion */
	display_morpion();
	
	/* Tant que ce n'est pas la fin de la partie, on continue */
	while(!is_end())
	{
		/* On change de joueur */
		if(to_play == SECOND_PLAYER)
			to_play = FIRST_PLAYER;
		else
			to_play++; // on passe de 0 à 1 (premier tour, to_play était à 0) ou de 1 à 2
		
		/* On demande pour jouer (ou on fait jouer l'IA si il y en a une et que c'est à elle de jouer) */
		ask_to_play();
		
		/* On affiche l'etat du morpion */
		display_morpion();
	}
	
	/* Si il y a un gagnant, on l'affiche, sinon on anonce que le match est nul. */
	if(is_there_winner())
		printf("\nLe joueur %d a gagné !\n", to_play);
	else
		printf("\nIl n'y a aucun gagnant..\n");

	return 0;
}
