/* TP - Attracteurs du tic-tac-toe */

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

/* codage des pions : vide : 0, X : 1, O : 2 */

/* Adam joue les X */ 

/* stockage des informations
   -3 : le sommet est invalide
   -2 : partie terminée nulle
   -1 : partie non terminée qui n'est pas dans l'attracteur 
   0, 1, 2, 3 ... : plus petit attracteur Ai contenant le sommet */

#define N 19683 // 3^9

int attractA[N];
int attractE[N];

void affiche(int ttt[3][3]){
    char symb[3] = {' ', 'X', 'O'};
    printf("-------\n");
    for (int i = 0; i < 3; i+=1) {
        for (int j = 0; j < 3; j += 1) {
            printf("|%c", symb[ttt[i][j]]);
        }
        printf("|\n");
    }
    printf("-------\n");
}


/* PARTIE 1 - codage / décodage */

int codage(int ttt[3][3]){
    // A FAIRE
    return 0;
} 

void decodage(int c, int ttt[3][3]){
    // A FAIRE
}

void testCodage(){
    int ttt[3][3] = {{0,1,1}, {2,0,2}, {0,1,2}};
    affiche(ttt);
    assert(codage(ttt) == 3461);
    int t[3][3];
    decodage(3461, t);
    affiche(t);
    for (int i = 0; i < 3; i += 1){
        for (int j = 0; j < 3; j += 1){
            assert(t[i][j] == ttt[i][j]);
        }
    }
}

/* PARTIE 2 - information sur les plateaux */

bool etatGagnant(int ttt[3][3], int J) {
    // teste les lignes
    for (int i = 0; i < 3; i += 1) {
        if ((ttt[i][0] == J) && (ttt[i][1] == J) && (ttt[i][2] == J)) {
            return true;
        }
    }
    // teste les colonnes
    for (int j = 0; j < 3; j += 1) {
        if ((ttt[0][j] == J) && (ttt[1][j] == J) && (ttt[2][j] == J)) {
            return true;
        }
    }
    // teste les diagonales
    if ((ttt[0][0] == J) && (ttt[1][1] == J) && (ttt[2][2] == J)) {
        return true;
    } else if ((ttt[0][2] == J) && (ttt[1][1] == J) && (ttt[2][0] == J)) {
        return true;
    } else {
        return false;
    }
}

// compte le nombre de 0/1/2 dans la grille
void comptage(int ttt[3][3], int* n0, int* n1, int* n2){
    // A FAIRE
}

// initialisation des tableaux attractA et attractE
void init(){ 
    // valide les états, et indique les grilles gagnantes
    for (int i = 0; i < N; i += 1){
        int ttt[3][3];
        decodage(i, ttt);
        int n0, n1, n2;
        // A COMPLETER
        // ...
    }
}


/* PARTIE 3 - calcul des attracteurs */

// calcule l'attracteur Ak : renvoie true si de nouveaux états attracteurs ont été trouvés
bool attracK(int attract[N], int J, int K) {
    bool nouv = false; // nouvel etat détecté ?
    for (int i = 0; i < N; i += 1) {
        if (attract[i] == -1){
            // A COMPLETER : attract[i] = k ??

        }
    }
    return nouv;
}

void attracteurs(){ 
    // A FAIRE
}

/* PARTIE 4 - Jeu humain vs IA */

void joueIA(int ttt[3][3], int J) {
    // si on est dans l'attracteur J, on cherche à descendre strictement (position gagnante)
    // si on est dans l'attracteur adverse, normalement, impossible d'en sortir 
    // si on n'est pas dans un attracteur, normalement, on ne peut pas entrer dans le sien, et il ne faut pas aller dans celui de l'adversaire
    int c = codage(ttt);
    int* attract = J == 1 ? attractA : attractE;
    int* attractAdv = J == 1 ? attractE : attractA;
    int att = attract[c]; int attv = attractAdv[c];
    if (att >= 0) {
        printf("IA : je vais vous battre en moins de %d coups !\n", att);
        /* A compléter */

    } else if (attv >= 0) {
        printf("IA : hmm, vous êtes bien parti ... \n");
        /*  A compléter */

    } else {
        assert((att == -1) && (attv == -1));
        printf("IA : c'est serré ... \n");
        /* A compléter */

    }
}


/* joue à l'emplacement lig / col */
bool joue(int ttt[3][3], int lig, int col, int J) {
    if ((lig >= 0) && (lig < 3) && (col >= 0) && (col < 3) && ttt[lig][col] == 0){
        ttt[lig][col] = J;
        return true;
    } else {
        return false;
    }
}

void joueHumain(int ttt[3][3], int J){
    bool ok = false;
    while (!ok) {
        int lig, col;
        printf("A vous : ligne, colonne\n");
        if (scanf("%d,%d", &lig, &col) == 2) {
            ok = joue(ttt, lig, col, J);
        } else {
            while (getchar() != EOF);
        }
        if (!ok) {
            printf("Erreur de saisie\n");
        }
    }
}

void tictactoe() {
    int ttt[3][3] = {{0,0,0},{0,0,0},{0,0,0}};
    int n = 0;  // nombre de coups joués
    int IA = 1; // identité de l'IA
    printf("Voulez-vous commencer ? (o/n)\n");
    char rep;
    if (scanf("%c", &rep) == 1) {
        if (rep == 'o') IA = 2; // l'IA joue Eve
    }
    int J = 1;  // joueur courant
    while (n < 9) {
        affiche(ttt);
        if (J == IA) {
            joueIA(ttt, J);
        } else {
            joueHumain(ttt, J);
        }
        if (etatGagnant(ttt, J)) break;
        J = 3 - J;
        n += 1;
    }
    // fin de partie
    affiche(ttt);
    if (etatGagnant(ttt, J)) {
        if (J == IA) {
            printf("Victoire IA !\n");
        } else {
            printf("Victoire Humain !\n");
        }
    } else {
        printf("Match nul ... \n");
    }
}

// fonction principale 

int main(){
    printf("TicTacToe\n");
    testCodage();

    // Initialisation de attractA et attractE
    init();
    
    // Statistiques sur les états finaux
    int nGA = 0; // gagnant pour A
    int nGE = 0; // gagnant pour E
    int nN = 0;  // partie nulle
    int nT = 0;  // partie valide
    for (int i = 0; i < N; i += 1){
        if (attractA[i] != -3) {
            nT += 1;
        }
        if (attractA[i] == 0) {
            nGA += 1;
        } else if (attractE[i] == 0) {
            nGE += 1;
        } else if (attractA[i] == -2) {
            nN += 1;
        }
    }
    printf("N:%d GA:%d GE:%d TOT:%d\n", nN, nGA, nGE, nT);

    printf("Calcul attracteurs\n");
    attracteurs();
    
    // Statistiques sur les attracteurs
    int cA = 0; // dans l'attracteur de A
    int cE = 0; // dans l'attracteur de E
    int cN = 0; // partie valide d'issue incertaine
    // A COMPLETER
    printf("N:%d A:%d E:%d TOT:%d\n", cN, cA, cE, cN + cA + cE);

    // jeu humain / IA

    // tictactoe();

    return 0;
}