#include <stdio.h>



#define NB_JOUEUR 4
#include <string.h>
#include <stdlib.h>
#include <time.h>
int input[5]= {0,0,0,0,0};

void _init_jeu ();

struct card_action{
    char nom[32];
    int indice;
    int nombre;
    };

struct card_adresse{
    int adresse;
    int indice;
    int nombre;
    };

struct card_plan{
    int est_valide[NB_JOUEUR];
    int points[2];
    int condition[25];
    void (*test)(struct card_plan*, int);
    int numero;
    int indice;
    int est_VA;
    };

   
struct scarte{
    int len_action;
    int len_adresse;
    int len_plan;
    struct card_action action[6];
    struct card_adresse adresse[15];
    struct card_plan plan[28];
    int carte_tire[6];
    int (*tirage)(struct scarte*);
};

typedef struct scarte S_cartes;

struct maison{
    int indice;
    int adresse;
    int status;
    int geometrie;
};

struct plt_allee{
    int nb_maison;
    int indice_piscine[3];
    int parcs[2];
    struct maison Maison[13];
};

struct plt{
    struct plt_allee allee[3];
    int indice_bis[9][3];
    int rond_point[2][3];
    int bonus_immo[6];
    int geo[6];
    int interim;
    int cpt_refus;
    int (*cpt_bis)(struct plt*);
    int (*cpt_geo)(struct plt*);
};

typedef struct plt S_Plateau;

struct game {
    S_Plateau Plateaux[NB_JOUEUR];
    S_cartes Cartes;
    int (*update)(struct game*);
};

typedef struct game S_Jeu;

S_Jeu Jeu;

void verif_plan(struct card_plan*, int);
void verif_plan1(struct card_plan*, int);
void verif_plan2(struct card_plan*, int);
void verif_plan3(struct card_plan*, int);
int compter_bis(S_Plateau*);
int compter_geometre(S_Plateau*);
int update_jeu(S_Jeu*);
int nouv_tirage(S_cartes*);


void _init_jeu () {

    srand(time(NULL));
   
//###########################################################################################################################################################################################

//                                                          INIT sCARTES

//###########################################################################################################################################################################################

    Jeu.Cartes.len_action=81;
    Jeu.Cartes.len_adresse=81;
    Jeu.Cartes.len_plan=28;

    char cardname[6][32]={"Géomètre","Agent immobilier","Paysagiste","Fabricant de piscine","Agence d’intérim","Numéro Bis"};
    int i,j;
    for (i=0;i<6;i++){
        strcpy(Jeu.Cartes.action[i].nom, cardname[i]);Jeu.Cartes.action[i].indice=i;
        if (i<3)
            Jeu.Cartes.action[i].nombre=18;
        else
            Jeu.Cartes.action[i].nombre=9;
    }
    for (i=0;i<15;i++){
        Jeu.Cartes.adresse[i].indice=i;Jeu.Cartes.adresse[i].adresse=i+1;
        if (i<2)
            Jeu.Cartes.adresse[i].nombre=3;
        else {
            if (i<8)
                Jeu.Cartes.adresse[i].nombre=i+2;
            else
                Jeu.Cartes.adresse[i].nombre=16-i;
        }
    }
    Jeu.Cartes.adresse[14].nombre=3;
    const int lst_condition[18][6] = {
        // --- Plans N°1 (Indices 0 à 5) ---
        {6, 0, 0, 0, 0, 0}, // Indice 0 : Six lotissements de 1
        {0, 4, 0, 0, 0, 0}, // Indice 1 : Quatre lotissements de 2
        {0, 0, 3, 0, 0, 0}, // Indice 2 : Trois lotissements de 3
        {0, 0, 0, 2, 0, 0}, // Indice 3 : Deux lotissements de 4
        {0, 0, 0, 0, 2, 0}, // Indice 4 : Deux lotissements de 5
        {0, 0, 0, 0, 0, 2}, // Indice 5 : Deux lotissements de 6
       
        // --- Plans N°2 (Indices 6 à 11) ---
        {3, 0, 0, 0, 0, 1}, // Indice 6 : Trois de 1 + Un de 6
        {0, 2, 0, 0, 1, 0}, // Indice 7 : Deux de 2 + Un de 5
        {0, 0, 1, 1, 0, 0}, // Indice 8 : Un de 3 + Un de 4
        {0, 0, 0, 1, 1, 0}, // Indice 9 : Un de 4 + Un de 5
        {4, 0, 0, 1, 0, 0}, // Indice 10: Quatre de 1 + Un de 4
        {0, 0, 2, 1, 0, 0}, // Indice 11: Deux de 3 + Un de 4
       
        // --- Plans N°3 (Indices 12 à 17) ---
        {1, 1, 0, 0, 0, 1}, // Indice 12: Un de 1 + Un de 2 + Un de 6
        {1, 2, 1, 0, 0, 0}, // Indice 13: Un de 1 + Deux de 2 + Un de 3
        {2, 1, 1, 0, 0, 0}, // Indice 14: Deux de 1 + Un de 2 + Un de 3
        {0, 1, 1, 0, 1, 0}, // Indice 15: Un de 2 + Un de 3 + Un de 5
        {1, 0, 0, 1, 1, 0}, // Indice 16: Un de 1 + Un de 4 + Un de 5
        {0, 1, 1, 1, 0, 0}  // Indice 17: Un de 2 + Un de 3 + Un de 4
    };//nb quartier de {1,2,3,4,5,6} habitation
   
    for (i=0;i<28;i++){
        for (j=0;j<NB_JOUEUR;j++){
            Jeu.Cartes.plan[i].est_valide[j]=0;
        }
        if (i<18) {
            memcpy(Jeu.Cartes.plan[i].condition, lst_condition[i], sizeof(lst_condition[i]));
            Jeu.Cartes.plan[i].test=verif_plan;
        }
        else {
            switch (i) {
                case 18:{
                    Jeu.Cartes.plan[i].test=verif_plan1;
                    memcpy(Jeu.Cartes.plan[i].condition, (int[25]){25,
                        10, 50, 70, 90,
                        1, 21, 31, 41, 51, 61, 91, 101,
                        2, 12, 22, 32, 42, 52, 62, 72, 82, 92, 102, 112
                    }, 25 * sizeof(int));
                    break;
                }
                case 19: {
                    Jeu.Cartes.plan[i].test=verif_plan1;
                    memcpy(Jeu.Cartes.plan[i].condition, (int[24]){24,
                        0, 10, 20, 30, 40, 50, 60, 70, 80, 90,
                        1, 21, 31, 41, 51, 61, 91,
                        2, 22, 62, 82, 102, 112
                    }, 24 * sizeof(int));
                    break;
                }
                case 20: {
                    Jeu.Cartes.plan[i].test=verif_plan2;
                    memcpy(Jeu.Cartes.plan[i].condition, (int[24]){
                        5,
                        0
                    }, 2 * sizeof(int));
                    break;
                }
                case 21: {
                    Jeu.Cartes.plan[i].test=verif_plan2;
                    memcpy(Jeu.Cartes.plan[i].condition, (int[24]){
                        0,
                        7
                    }, 2 * sizeof(int));
                    break;
                }
                case 22: {
                    Jeu.Cartes.plan[i].test=verif_plan1;
                    memcpy(Jeu.Cartes.plan[i].condition, (int[24]){22,
                        0, 10, 50, 70, 90,
                        1, 21, 31, 41, 51, 61, 91, 101,
                        2, 12, 32, 52, 62, 92, 102, 112
                        }, 22 * sizeof(int));
                        break;
                }
                case 23: {
                    Jeu.Cartes.plan[i].test=verif_plan3;
                    memcpy(Jeu.Cartes.plan[i].condition, (int[24]){
                        4,
                        0,
                        2,
                        0
                    }, 4 * sizeof(int));
                    break;
                }
                case 24: {
                    Jeu.Cartes.plan[i].test=verif_plan3;
                    memcpy(Jeu.Cartes.plan[i].condition, (int[24]){
                        4,
                        1,
                        1,
                        1
                    }, 4 * sizeof(int));
                    break;
                }
                case 25: {
                    Jeu.Cartes.plan[i].test=verif_plan3;
                    memcpy(Jeu.Cartes.plan[i].condition, (int[24]){
                        4,
                        2,
                        0,
                        0
                    }, 4 * sizeof(int));
                    break;
                }
                case 26: {
                    Jeu.Cartes.plan[i].test=verif_plan3;
                    memcpy(Jeu.Cartes.plan[i].condition, (int[24]){
                        3,
                        1,
                        1,
                        0
                    }, 4 * sizeof(int));
                    break;
                }
                case 27: {
                    Jeu.Cartes.plan[i].test=verif_plan3;
                    memcpy(Jeu.Cartes.plan[i].condition, (int[24]){
                        2,
                        1,
                        1,
                        0
                    }, 4 * sizeof(int));
                    break;
                }
            }
        }
        Jeu.Cartes.plan[i].indice=i;
        if (i<6){
            Jeu.Cartes.plan[i].numero=1;
            Jeu.Cartes.plan[i].est_VA=0;
        }
        else {
            if (i<12){
            Jeu.Cartes.plan[i].numero=2;
            Jeu.Cartes.plan[i].est_VA=0;
            }
            else{
                if (i<18){
                    Jeu.Cartes.plan[i].numero=3;
                    Jeu.Cartes.plan[i].est_VA=0;
                }
                else{
                    if (i<23){
                        Jeu.Cartes.plan[i].numero=1;
                        Jeu.Cartes.plan[i].est_VA=1;
                    }
                    else{
                        Jeu.Cartes.plan[i].numero=2;
                        Jeu.Cartes.plan[i].est_VA=1;
                       
                    }
                }
            }
        }
        int valeurs_points[28][2] = {
            {8,4}, {10,6}, {8,3}, {6,3}, {8,4}, {10,6},
            {10,6}, {12,7}, {8,4}, {9,5}, {9,5}, {12,7},
            {13,7}, {7,3}, {7,3}, {11,6}, {13,7}, {8,4},
            {6,3}, {7,4}, {10,6}, {8,4}, {6,3},
            {5,3}, {7,4}, {12,5}, {7,4}, {12,7}
        };
        Jeu.Cartes.plan[i].points[0] = valeurs_points[i][0];
        Jeu.Cartes.plan[i].points[1] = valeurs_points[i][1];
    }
   
    for(i=0; i<6; i++)
        Jeu.Cartes.carte_tire[i] = 0;
    Jeu.Cartes.tirage=nouv_tirage;
   
//###########################################################################################################################################################################################

//                                                          INIT sPLATEAUX

//###########################################################################################################################################################################################
    const int piscines_init[3][3] = {
        {2, 3, 7},   // Valeurs pour j = 0
        {3, 7, 10},  // Valeurs pour j = 1
        {1, 5, 10}   // Valeurs pour j = 2
    };
    int k;
    for (i=0;i<NB_JOUEUR;i++) {
        for (j=0;j<3;j++) {
            Jeu.Plateaux[i].allee[j].nb_maison=j+10;

            memcpy(Jeu.Plateaux[i].allee[j].indice_piscine, piscines_init[j], sizeof(piscines_init[j]));
           
            Jeu.Plateaux[i].allee[j].parcs[0]=0;Jeu.Plateaux[i].allee[j].parcs[1]=j+3;
            for (k=0;k<13;k++){
                Jeu.Plateaux[i].allee[j].Maison[k].indice=k;Jeu.Plateaux[i].allee[j].Maison[k].status=0;Jeu.Plateaux[i].allee[j].Maison[k].adresse=0;Jeu.Plateaux[i].allee[j].Maison[k].geometrie=0;
            }
            Jeu.Plateaux[i].allee[j].Maison[0].geometrie=1; Jeu.Plateaux[i].allee[j].Maison[13].geometrie=1;
        }
        for (j=0;j<9;j++) {
            for (k=0;k<3;k++){
            Jeu.Plateaux[i].indice_bis[j][k]=0;
            }
        }
        for (j=0;j<3;j++){
            Jeu.Plateaux[i].rond_point[0][j]=0;Jeu.Plateaux[i].rond_point[1][j]=0;
        }
        for (j=0;j<6;j++){
            Jeu.Plateaux[i].bonus_immo[0]=0;
            Jeu.Plateaux[i].geo[j]=0;
        }
        Jeu.Plateaux[i].cpt_bis=compter_bis;
        Jeu.Plateaux[i].cpt_geo=compter_geometre;
        Jeu.Plateaux[i].interim=0;
        Jeu.Plateaux[i].cpt_refus=0;
    }
    Jeu.update=update_jeu;
}



void verif_plan (struct card_plan *P, int plr) {
    if (P->est_valide[plr]!=0)
        return;
    
    int i;
    for (i=0;i<6;i++){
        if (P->condition[i]>Jeu.Plateaux[plr].geo[i])
            return;
    }
    for (i=0;i<NB_JOUEUR;i++) {
        if (P->est_valide[i]!=0) {
            P->est_valide[plr]=P->points[1];
            return;
        }
    }
    P->est_valide[plr]=P->points[0];
}

void verif_plan1 (struct card_plan *P, int plr) {
    if (P->est_valide[plr]!=0)
        return;
    
    int i;
    for (i=1;i<P->condition[0];i++) {
        if (Jeu.Plateaux[plr].allee[P->condition[i]%10].Maison[((P->condition[i])-(P->condition[i]%10))/10].adresse==0)
            return;
    }
    for (i=0;i<NB_JOUEUR;i++) {
        if (P->est_valide[i]!=0) {
            P->est_valide[plr]=P->points[1];
            return;
        }
    }
    P->est_valide[plr]=P->points[0];
}

void verif_plan2 (struct card_plan *P, int plr) {
    if (P->est_valide[plr]!=0)
        return;
                
    int i;
    int lst[2]={Jeu.Plateaux[plr].cpt_bis(&Jeu.Plateaux[plr]),Jeu.Plateaux[plr].cpt_geo(&Jeu.Plateaux[plr])};
   
    for (i=0;i<2;i++) {
        if (P->condition[i]>lst[i])
            return;
    }
    for (i=0;i<NB_JOUEUR;i++) {
        if (P->est_valide[i]!=0) {
            P->est_valide[plr]=P->points[1];
            return;
        }
    }
    P->est_valide[plr]=P->points[0];
}

void verif_plan3 (struct card_plan *P, int plr) {
    if (P->est_valide[plr]!=0)
        return;
    
    int i;
   
    if (P->condition[0]==4) {
        int j, lst[3]={0,0,0};
        for (i=0;i<3;i++) {
            for (j=0;j<12;j++)
                if (Jeu.Plateaux[plr].allee[i].Maison[j].status==2)
                    lst[0]+=1;
            lst[1]+=Jeu.Plateaux[plr].allee[i].parcs[0];
        }
        for (i=0;i<2;i++)
            if (Jeu.Plateaux[plr].rond_point[i][0]==1)
                lst[2]+=1;
        for (i=0;i<3;i++)
            if (P->condition[i+1]>lst[i])
                return;
    }
    else {
        int lst[3]={0,0,0};
        for (i=0;i<12;i++)
            if (Jeu.Plateaux[plr].allee[P->condition[0]].Maison[i].status==2)
                lst[0]+=1;
        lst[1]+=Jeu.Plateaux[plr].allee[P->condition[0]].parcs[0];
        for (i=0;i<3;i++)
            if (P->condition[i+1]>lst[i])
                return;
    }
    for (i=0;i<NB_JOUEUR;i++) {
        if (P->est_valide[i]!=0) {
            P->est_valide[plr]=P->points[1];
            return;
        }
    }
    P->est_valide[plr]=P->points[0];
}

int compter_bis(S_Plateau *P) {
    int cpt;
    for (cpt=0;cpt<9;cpt++) {
        if (P->indice_bis[cpt][0]==0)
            return cpt;
    }
    return 9;
}

int compter_geometre(S_Plateau *P) {
    int i,nb=0;
    for (i=0;i<6;i++) {
        nb+=P->geo[i];
    }
    return nb;
}

int nouv_tirage(S_cartes *P) {
    if (P->len_action < 3)
        return 0;
    
    int i,j;
    for (i=0;i<3;i++) {
        int cpt=0, nb=(rand()%(P->len_action));
        for (j=0;j<6;j++){
            cpt+=P->action[j].nombre;
            if (cpt>nb){
                P->carte_tire[i]=P->action[j].indice;
                P->action[j].nombre-=1;
                P->len_action-=1;
                break;
            }
        }
        cpt=0;nb=(rand()%(P->len_adresse));
        for (j=0;j<15;j++){
            cpt+=P->adresse[j].nombre;
            if (cpt>nb){
                P->carte_tire[i+3]=P->adresse[j].indice;
                P->adresse[j].nombre-=1;
                P->len_adresse-=1;
                break;
            }
        }
    }
    return 1;
}

int update_est_valide(S_Jeu *P, int ijoueur, int iallee, int imaison, int iadresse) {
    int i;
    for (i=imaison ; i < P->Plateaux[ijoueur].allee[iallee].nb_maison ; i++) {
        if (P->Plateaux[ijoueur].allee[iallee].Maison[i].status) {
            
            if (P->Plateaux[ijoueur].allee[iallee].Maison[i].status==3)
                break;
            
            if (P->Plateaux[ijoueur].allee[iallee].Maison[i].adresse > P->Cartes.adresse[iadresse].adresse)
                return 0;
        }
    }
    
    for (i = imaison ; i >= 0 ; i--) {
        if (P->Plateaux[ijoueur].allee[iallee].Maison[i].status) {
            
            if (P->Plateaux[ijoueur].allee[iallee].Maison[i].status==3)
                break;
            
            if (P->Plateaux[ijoueur].allee[iallee].Maison[i].adresse < P->Cartes.adresse[iadresse].adresse)
                return 0;
        }
    }
    P->Plateaux[ijoueur].allee[iallee].Maison[i].adresse = P->Cartes.adresse[iadresse].adresse;
    P->Plateaux[ijoueur].allee[iallee].Maison[i].status = 1;
    return 1;
}

int update_jeu(S_Jeu *P) { //format input[5]={indice joueur, indice allee, indice maison, indice action, action}
    int i, ijoueur=input[0],iallee=input[1],imaison=input[2],iaction=P->Cartes.carte_tire[input[3]],iadresse=P->Cartes.carte_tire[input[3]+3];
    
    if (P->Plateaux[ijoueur].allee[iallee].Maison[imaison].status!=0)
        return 0;
    
    switch (iaction) {
        case 0: {
            if ((P->Plateaux[ijoueur].allee[input[4]%10].Maison[((input[4])-(input[4]%10))/10].geometrie==0) && update_est_valide(P, ijoueur, iallee, imaison, iadresse)) {
                P->Plateaux[ijoueur].allee[input[4]%10].Maison[((input[4])-(input[4]%10))/10].geometrie=1;
            }
            else 
                return 0;
            break;
        }
        
        case 1: {
            if (((P->Plateaux[ijoueur].bonus_immo[input[4]]<=input[4]) && (P->Plateaux[ijoueur].bonus_immo[input[4]] < 4)) && update_est_valide(P, ijoueur, iallee, imaison, iadresse)) {
                P->Plateaux[ijoueur].bonus_immo[input[4]]+=1;
            }
            else
                return 0;
            break;
        }
        
        case 2: {
            if ((P->Plateaux[ijoueur].allee[iallee].parcs[0]!=P->Plateaux[ijoueur].allee[iallee].parcs[1]) && update_est_valide(P, ijoueur, iallee, imaison, iadresse))
                P->Plateaux[ijoueur].allee[iallee].parcs[0]+=1;
            else 
                return 0;
            break;
        }
        
        case 3: {
            for (i=0;i<3;i++) {
                if ((P->Plateaux[ijoueur].allee[iallee].indice_piscine[i]==imaison) && update_est_valide(P, ijoueur, iallee, imaison, iadresse))
                    P->Plateaux[ijoueur].allee[iallee].Maison[imaison].status=2;
            }
            if (P->Plateaux[ijoueur].allee[iallee].Maison[imaison].status!=2)
                return 0;
            return 1;
        }
        case 4: {
            if (input[4]==3)
                return 0;
            int nouv_adresse=P->Cartes.adresse[iadresse].adresse + input[4] - 3;
            
            if (!update_est_valide(P, ijoueur, iallee, imaison, nouv_adresse))
                return 0;
            
            P->Plateaux[ijoueur].interim+=1;
            return 1;
        }

        case 5: {
            if (!update_est_valide(P, ijoueur, iallee, imaison, iadresse))
                return 0;
            
            if ((((input[4])-(input[4]%10))/10>0) && (P->Plateaux[ijoueur].allee[input[4]%10].Maison[(((input[4])-(input[4]%10))/10)-1].status!=0)) {
                P->Plateaux[ijoueur].indice_bis[P->Plateaux[ijoueur].cpt_bis(&P->Plateaux[ijoueur])][0]=1;
                P->Plateaux[ijoueur].indice_bis[P->Plateaux[ijoueur].cpt_bis(&P->Plateaux[ijoueur])][1]=input[4]%10;
                P->Plateaux[ijoueur].indice_bis[P->Plateaux[ijoueur].cpt_bis(&P->Plateaux[ijoueur])][2]=((input[4])-(input[4]%10))/10;
                P->Plateaux[ijoueur].allee[input[4]%10].Maison[(((input[4])-(input[4]%10))/10)].adresse=P->Plateaux[ijoueur].allee[input[4]%10].Maison[(((input[4])-(input[4]%10))/10)-1].adresse;
                P->Plateaux[ijoueur].allee[input[4]%10].Maison[(((input[4])-(input[4]%10))/10)].status=4;
            }
            else {
                if ((((input[4])-(input[4]%10))/10<11) && (P->Plateaux[ijoueur].allee[input[4]%10].Maison[(((input[4])-(input[4]%10))/10)+1].status!=0)) {
                    P->Plateaux[ijoueur].indice_bis[P->Plateaux[ijoueur].cpt_bis(&P->Plateaux[ijoueur])][0]=1;
                    P->Plateaux[ijoueur].indice_bis[P->Plateaux[ijoueur].cpt_bis(&P->Plateaux[ijoueur])][1]=input[4]%10;
                    P->Plateaux[ijoueur].indice_bis[P->Plateaux[ijoueur].cpt_bis(&P->Plateaux[ijoueur])][2]=((input[4])-(input[4]%10))/10;
                    P->Plateaux[ijoueur].allee[input[4]%10].Maison[(((input[4])-(input[4]%10))/10)].adresse=P->Plateaux[ijoueur].allee[input[4]%10].Maison[(((input[4])-(input[4]%10))/10)+1].adresse;
                    P->Plateaux[ijoueur].allee[input[4]%10].Maison[(((input[4])-(input[4]%10))/10)].status=4;
                }
                else {
                    P->Plateaux[ijoueur].allee[iallee].Maison[i].adresse = 0;
                    P->Plateaux[ijoueur].allee[iallee].Maison[i].status = 0;
                    return 0;
                }
            }
            return 1;
        }
    }
    
    P->Plateaux[ijoueur].allee[iallee].Maison[imaison].adresse=P->Cartes.adresse[iadresse].adresse;
    if (P->Plateaux[ijoueur].allee[iallee].Maison[imaison].status==0)
        P->Plateaux[ijoueur].allee[iallee].Maison[imaison].status=1;
    
    return 1;
}



// ======================================================================
// ======================================================================
// DEBUT FONCTION DE TESTS (CORRIGEE)
// ======================================================================
// ======================================================================

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

#define TEST_ASSERT_INT(actual, expected, msg) \
    do { \
        int _a = (actual); \
        int _e = (expected); \
        if (_a != _e) { \
            printf("[ECHEC] %s\n  -> Attendu: %d, Obtenu: %d\n", msg, _e, _a); \
        } else { \
            printf("[SUCCES] %s\n", msg); \
        } \
    } while(0)

// Fonction utilitaire pour truquer la pioche (index_choix = de 0 à 2)
void forcer_tirage(int index_choix, int indice_action, int adresse_valeur) {
    Jeu.Cartes.carte_tire[index_choix] = indice_action;
    
    // On cherche l'indice de la carte adresse qui correspond à la valeur voulue
    int target_idx = 0;
    for(int i=0; i<15; i++) {
        if(Jeu.Cartes.adresse[i].adresse == adresse_valeur) {
            target_idx = Jeu.Cartes.adresse[i].indice;
            break;
        }
    }
    Jeu.Cartes.carte_tire[index_choix + 3] = target_idx;
}

#include <stdio.h>

// On simule une rue de 12 maisons.
// 0 = vide, 1 = construit, 3 = rond-point
//int status[12] =  { 0,  1,  0,  1,  0,  0,  0,  1,  0,  0,  0,  1 };
//int adresse[12] = { 0, 13,  0, 10,  0,  0,  0,  6,  0,  0,  0,  3 };
// Index mémoires:  0   1   2   3   4   5   6   7   8   9  10  11

// Fonction d'affichage visuel (car le cerveau lit mieux les dessins que les chiffres)
void afficher_rue(int allee, int joueur) {
    printf("\n============= AFFICHAGE PHYSIQUE DE LA RUE =============\n");
    printf("        <-- GAUCHE (Debut)          DROITE (Fin) -->\n\n");
    
    printf("Index : ");
    for(int i = 11; i >= 0; i--) printf("[%2d] ", i);
    
    printf("\nNum   : ");
    for(int i = 11; i >= 0; i--) {
        if(Jeu.Plateaux[joueur].allee[allee].Maison[i].status == 0) printf("  -  ");
        else if (Jeu.Plateaux[joueur].allee[allee].Maison[i].status == 3) printf(" (R) ");
        else printf(" %2d  ", Jeu.Plateaux[joueur].allee[allee].Maison[i].adresse);
    }
    printf("\n========================================================\n");
}



// ======================================================================
// L'AUDITEUR ABSOLU (Vérification des Invariants)
// ======================================================================
// Cette fonction scanne le plateau et vérifie que la réalité physique 
// du jeu Welcome To est respectée, quoi qu'il arrive.
int auditer_plateau(S_Jeu *P, int ijoueur) {
    for (int a = 0; a < 3; a++) {
        int val_droite = 999; // On commence à droite (Index 0), la valeur max théorique
        int status_droite = 0;

        for (int m = 0; m < P->Plateaux[ijoueur].allee[a].nb_maison; m++) {
            int status_actuel = P->Plateaux[ijoueur].allee[a].Maison[m].status;
            int val_actuelle = P->Plateaux[ijoueur].allee[a].Maison[m].adresse;

            if (status_actuel == 3) {
                // C'est un rond-point. La rue est coupée, on réinitialise la valeur max.
                val_droite = 999; 
                status_droite = 3;
                continue;
            }

            if (status_actuel != 0) { // Si la maison est construite (Normal, Piscine ou Bis)
                // REGLE 1 : L'ordre croissant (lu de droite à gauche, donc décroissant)
                if (val_actuelle > val_droite) {
                    printf("[AUDIT FATAL] Allee %d : %d a l'index %d est > %d a sa droite !\n", a, val_actuelle, m, val_droite);
                    return 0; // ECHEC !
                }
                
                // REGLE 2 : L'unicité des numéros (sauf Numéro Bis)
                if (val_actuelle == val_droite) {
                    if (status_actuel != 4 && status_droite != 4) {
                        printf("[AUDIT FATAL] Allee %d : Doublon illegal de %d a l'index %d sans status Bis !\n", a, val_actuelle, m);
                        return 0; // ECHEC !
                    }
                }

                val_droite = val_actuelle;
                status_droite = status_actuel;
            }
        }
    }
    return 1; // Le plateau est structurellement parfait
}


// ======================================================================
// LE TEST DU SINGE (FUZZING)
// ======================================================================
// On va simuler 10 000 coups complètement aléatoires (légaux et illégaux).
// Si update_jeu() plante ou si l'auditeur trouve une faille, le test échoue.
void test_fuzzing_infaillible() {
    printf("\n--- SCENARIO GLOBAL : FUZZING (10 000 COUPS ALEATOIRES) ---\n");
    _init_jeu();
    
    int coups_valides = 0;
    int coups_refuses = 0;
    int crash = 0;

    for (int i = 0; i < 100000; i++) {
        // 1. On remplit le deck artificiellement si besoin (car on va piocher beaucoup)
        if (Jeu.Cartes.len_action < 3) _init_jeu(); 
        
        nouv_tirage(&Jeu.Cartes); // Tirage normal

        for (i=0;i<4;i++) {
    
            // 2. Génération d'un input 100% aléatoire
            input[0] = i; // Joueur au hasard
            input[1] = rand() % 3;         // Allée au hasard (0 à 2)
            input[2] = rand() % 12;        // Maison au hasard (0 à 11, on inclut le 11 pour tester les limites)
            input[3] = rand() % 3;         // Carte choisie (0 à 2)
            
            // Pour input[4] (l'action spéciale), on génère aussi du chaos
            int action_actuelle = Jeu.Cartes.carte_tire[input[3]];
            if (action_actuelle == 5) {
                input[4] = (rand() % 13) * 10 + (rand() % 3); // Format Bis (Maison*10 + Allée)
            } else if (action_actuelle == 4) {
                input[4] = rand() % 7; // Intérim (0 à 6)
            } else if (action_actuelle == 0) {
                input[4] = (rand() % 13) * 10 + (rand() % 3); // Géomètre
            } else {
                input[4] = rand() % 6; // Immo ou autre
            }
    
            // 3. On tente de jouer ce coup absurde
            // L'astuce : On se fiche de savoir si update_jeu renvoie 0 ou 1.
            // On veut juste s'assurer qu'il ne CRASH pas.
            int res = update_jeu(&Jeu);
            if (res == 1) coups_valides++;
            else coups_refuses++;
    
            // 4. VERIFICATION ABSOLUE
            // Après CE coup, le plateau du joueur est-il toujours physiquement cohérent ?
            if (auditer_plateau(&Jeu, input[0]) == 0) {
                printf("\n[!!!] FAIL : LE FUZZER A CASSE LE JEU AU COUP %d [!!!]\n", i);
                printf("Input fautif : J=%d, Allee=%d, Maison=%d, Choix=%d, Spé=%d\n", input[0], input[1], input[2], input[3], input[4]);
                crash = 1;
                break;
            }
        }
        if (auditer_plateau(&Jeu, input[0]) == 0) break;
    }

    TEST_ASSERT_INT(crash, 0, "Le Fuzzer n'a pas reussi a corrompre le plateau !");
    printf("  -> Stats du Singe : %d coups legaux trouves, %d coups bloques par le moteur.\n\n", coups_valides, coups_refuses);
    afficher_rue(input[1],input[0]);
}

// ======================================================================
// PARTIE PARFAITE (E2E)
// ======================================================================
// Un scénario E2E (End-to-End) qui simule une vraie partie stratégique
// pour valider qu'on peut remplir une rue entièrement et marquer les points.
void test_partie_parfaite() {
    printf("\n--- SCENARIO GLOBAL : LA PARTIE PARFAITE ---\n");
    _init_jeu();
    
    int j = 0; // Joueur 0
    int allee = 0; // On va remplir l'allée 0 (10 maisons) de 15 à 6

    // On va forcer un placement de la maison index 0 à l'index 9 (Droite à Gauche)
    int valeurs[10] = {15, 14, 13, 12, 11, 10, 9, 8, 7, 6};

    for (int i = 0; i < 10; i++) {
        forcer_tirage(0, 2, valeurs[i]); // Action Paysagiste, numéro décroissant
        input[0] = j; input[1] = allee; input[2] = i; input[3] = 0; input[4] = 0;
        
        int res = update_jeu(&Jeu);
        if(res == 0) {
            printf("Echec inattendu a l'index %d pour la valeur %d\n", i, valeurs[i]);
            TEST_ASSERT_INT(res, 1, "Remplissage parfait de la rue a echoue");
            return;
        }
    }

    TEST_ASSERT_INT(1, 1, "La rue de 10 maisons a ete remplie sans erreur");
    
    // Vérification de la validation d'un plan
    // Le plan 1 (Indice 1) demande : Quatre lotissements de 2.
    // L'allée 0 a 10 maisons consécutives. 
    // Mettons des barrières pour couper en lotissements de 2.
    Jeu.Plateaux[j].allee[allee].Maison[1].geometrie = 1;
    Jeu.Plateaux[j].allee[allee].Maison[3].geometrie = 1;
    Jeu.Plateaux[j].allee[allee].Maison[5].geometrie = 1;
    Jeu.Plateaux[j].allee[allee].Maison[7].geometrie = 1;

    // Simulation comptage externe (si pas appelé ailleurs)
    Jeu.Plateaux[j].geo[1] = 4; // Triche pour simuler les 4 lotissements de taille 2

    verif_plan(&Jeu.Cartes.plan[1], j);
    TEST_ASSERT_INT(Jeu.Cartes.plan[1].est_valide[j], Jeu.Cartes.plan[1].points[0], "Le joueur valide le plan grace a sa partie parfaite !");
}

int main() {
    printf("=================================================\n");
    printf("       BANC DE TESTS DE NIVEAU INGENIERIE        \n");
    printf("=================================================\n");

    test_partie_parfaite();
    test_fuzzing_infaillible();

    printf("\n=================================================\n");
    printf("                  FIN DES TESTS                  \n");
    printf("=================================================\n");

    return 0;
}

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: