-
-
Save Meithal/476894ff04ba51e72455a9fa33e015fe to your computer and use it in GitHub Desktop.
p4
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <ctype.h> | |
#include <time.h> | |
#define LARGEUR_DAMIER (17) | |
#define HAUTEUR_DAMIER (16) | |
#define LONGUEUR_DAMIER (LARGEUR_DAMIER * HAUTEUR_DAMIER) | |
#define LONGUEUR_VICTOIRE (4) | |
#define NOMBRE_JOUEURS (2) | |
#define CASE_VIDE ' ' | |
#define CASE_JOUEUR_1 'X' | |
#define CASE_JOUEUR_2 'O' | |
enum { | |
DIRECTION_NORD = 0, | |
DIRECTION_NORD_EST = 1, | |
DIRECTION_EST = 2, | |
DIRECTION_SUD_EST = 3, | |
DIRECTION_SUD = 4, | |
DIRECTION_SUD_OUEST = 5, | |
DIRECTION_OUEST = 6, | |
DIRECTION_NORD_OUEST = 7, | |
NOMBRE_DIRECTIONS = 8 | |
}; | |
struct case_damier { | |
char contenu; | |
long index; | |
long ligne; | |
long colonne; | |
} damier[LARGEUR_DAMIER * HAUTEUR_DAMIER]; | |
struct curseur { | |
struct case_damier * soi; | |
struct case_damier * directions[NOMBRE_DIRECTIONS]; | |
} curseur; | |
struct joueur { | |
char humain; | |
char symbole; | |
int long poids_colonne[LARGEUR_DAMIER]; // taille max de la ligne constituée | |
int long tous_les_poids_colonne[LARGEUR_DAMIER][4]; | |
int long poids_futur_pour_adversaire[LARGEUR_DAMIER]; // | |
int long poids_futur_pour_soi[LARGEUR_DAMIER]; | |
int long poids_max; | |
long int index_max; | |
} joueurs[NOMBRE_JOUEURS]; | |
int joueur_actif_i = 0; | |
void assigne_curseur(struct case_damier * soi) { | |
for (int i = 0 ; i < NOMBRE_DIRECTIONS ; ++i) { | |
curseur.directions[i] = NULL; | |
} | |
curseur.soi = soi; | |
if (soi->colonne > 0) | |
curseur.directions[DIRECTION_OUEST] = &damier[soi->index - 1]; | |
if (soi->colonne < LARGEUR_DAMIER - 1) { | |
curseur.directions[DIRECTION_EST] = &damier[soi->index + 1]; | |
} | |
if (soi->ligne > 0) { | |
curseur.directions[DIRECTION_NORD] = &damier[soi->index - LARGEUR_DAMIER]; | |
if (soi->colonne < LARGEUR_DAMIER - 1) | |
curseur.directions[DIRECTION_NORD_EST] = &damier[soi->index - LARGEUR_DAMIER + 1]; | |
if (soi->colonne > 0) | |
curseur.directions[DIRECTION_NORD_OUEST] = &damier[soi->index - LARGEUR_DAMIER - 1]; | |
} | |
if (soi->ligne < HAUTEUR_DAMIER - 1) { | |
curseur.directions[DIRECTION_SUD] = &damier[soi->index + LARGEUR_DAMIER]; | |
if (soi->colonne > 0) { | |
curseur.directions[DIRECTION_SUD_OUEST] = &damier[soi->index + LARGEUR_DAMIER - 1]; | |
} | |
if (soi->colonne < LARGEUR_DAMIER - 1) | |
curseur.directions[DIRECTION_SUD_EST] = &damier[soi->index + LARGEUR_DAMIER + 1]; | |
} | |
} | |
/* | |
* Calcule le poids reel d'une case en tenant compte des predictions futures, de la somme, etc. | |
*/ | |
/* | |
* Cette fonction retourne une structure contenant l'index et la valeur la plus hautes du tableau | |
* dont les bornes sont passées en paramètre. En cas d'égalitié, lance un jet de dés équitable | |
* pour sélectionner au hasard une des plus grandes valeurs contenues dans le tableau | |
*/ | |
struct max_struct { | |
ptrdiff_t index; | |
int long value; | |
int long max_count; | |
} last_max; | |
struct max_struct max_eq(int long * int_array_start, const int long * int_array_end) { | |
int max_count = 0; | |
int long * cur_max_a = NULL; | |
for (int long * i = int_array_start ; i <= int_array_end ; ++i) { | |
if (cur_max_a == NULL || *i > *cur_max_a) { | |
cur_max_a = i; | |
max_count = 1; | |
} | |
else if (*i == *cur_max_a) { | |
++max_count; | |
if (rand() < RAND_MAX / max_count) | |
cur_max_a = i; | |
} | |
} | |
ptrdiff_t taille = int_array_end - int_array_start; | |
ptrdiff_t index = taille - (int_array_end - cur_max_a); | |
last_max.index = index; | |
last_max.value = *(int_array_start + index); | |
last_max.max_count = max_count; | |
return last_max; | |
} | |
enum { | |
DOIT_AFFICHER_NUMEROS = (unsigned)0x01, /* 0b00001 */ | |
DOIT_AFFICHER_CASE = (unsigned)0x02, /* 0b00010 */ | |
DOIT_AFFICHER_FIN_LIGNE = (unsigned)0x04, /* 0b00100 */ | |
DOIT_AFFICHER_SEPARATION_HORIZONTALE = (unsigned)0x08, /* 0b01000 */ | |
}; | |
char * damier_packe[LARGEUR_DAMIER * HAUTEUR_DAMIER] = {'\0'}; | |
void pack_damier(void) { | |
for(struct case_damier * c = &damier[0] ; c < &damier[LARGEUR_DAMIER * HAUTEUR_DAMIER] ; ++c) { | |
*damier_packe[&damier[LARGEUR_DAMIER * HAUTEUR_DAMIER] - c] = c->contenu; | |
} | |
} | |
void depack_damier(void) { | |
for (char * contenu_case = * damier_packe ; | |
contenu_case < damier_packe[LARGEUR_DAMIER * HAUTEUR_DAMIER] ; | |
++contenu_case) { | |
damier[damier_packe[LARGEUR_DAMIER * HAUTEUR_DAMIER] - contenu_case].contenu = * contenu_case; | |
} | |
} | |
void afficher_ponderations() { | |
for (int joueur_i = 0; joueur_i < NOMBRE_JOUEURS ; ++joueur_i) { | |
printf("Poids pour le joueur %d (%c)\n", joueur_i, joueurs[joueur_i].symbole); | |
for(long * p = &joueurs[joueur_i].poids_colonne[0] ; p < &joueurs[joueur_i].poids_colonne[LARGEUR_DAMIER]; ++p) { | |
printf("Poids colonne %2ld : %ld\n", LARGEUR_DAMIER + 1 - (&joueurs[joueur_i].poids_colonne[LARGEUR_DAMIER] - p), *p); | |
} | |
} | |
} | |
void afficher_damier() { | |
unsigned int DRAPEAUX; | |
unsigned int TACHE; | |
int damier_i = -1; | |
do { | |
DRAPEAUX = 0; | |
if (damier_i == -1 || damier_i == LONGUEUR_DAMIER) | |
DRAPEAUX |= DOIT_AFFICHER_NUMEROS; | |
if (damier_i >= 0 && damier_i < LONGUEUR_DAMIER) | |
DRAPEAUX |= DOIT_AFFICHER_CASE; | |
if (((damier_i + 1) % LARGEUR_DAMIER) == 0 && damier_i != -1) | |
DRAPEAUX |= DOIT_AFFICHER_FIN_LIGNE; | |
if (damier_i == -1 || ((damier_i + 1) % LARGEUR_DAMIER) == 0) | |
DRAPEAUX |= DOIT_AFFICHER_SEPARATION_HORIZONTALE; | |
TACHE = 0; | |
while (DRAPEAUX) { | |
for (unsigned i = 0 ; i < 8 ; ++i) { | |
if (DRAPEAUX & ((unsigned) 1 << i)) { | |
TACHE = (unsigned) 1 << i; | |
DRAPEAUX ^= (unsigned) 1 << i; | |
break; | |
} | |
} | |
switch (TACHE) { | |
case DOIT_AFFICHER_NUMEROS: | |
printf(" "); | |
for (int j = 1; j <= LARGEUR_DAMIER; ++j) { | |
printf("%-4d", j); | |
} | |
putchar('\n'); | |
break; | |
case DOIT_AFFICHER_CASE: | |
printf("| %c ", damier[damier_i].contenu); | |
fflush(stdout); | |
break; | |
case DOIT_AFFICHER_FIN_LIGNE: | |
puts("|"); | |
break; | |
case DOIT_AFFICHER_SEPARATION_HORIZONTALE: | |
for (int j = 1; j <= LARGEUR_DAMIER; ++j) { | |
printf("+---"); | |
} | |
puts("+"); | |
break; | |
default: | |
break; | |
} | |
} | |
} while (damier_i++ <= LONGUEUR_DAMIER); | |
} | |
void faire_tomber_curseur_jusque_case_vide(long colonne) { | |
assigne_curseur(&damier[colonne]); | |
while (curseur.directions[DIRECTION_SUD] != NULL | |
&& curseur.directions[DIRECTION_SUD]->contenu == CASE_VIDE) { | |
assigne_curseur(curseur.directions[DIRECTION_SUD]); | |
} | |
} | |
void longueur_suite(struct joueur * pJoueur, int long sens[4]) { | |
int longueur; | |
struct case_damier * position_initiale = curseur.soi; | |
sens[0] = 1; | |
sens[1] = 1; | |
sens[2] = 1; | |
sens[3] = 1; | |
for (int direction = 0 ; direction < NOMBRE_DIRECTIONS ; direction++) { | |
assigne_curseur(position_initiale); | |
longueur = 0; | |
while(curseur.directions[direction] != NULL | |
&& curseur.directions[direction]->contenu == pJoueur->symbole) { | |
assigne_curseur(curseur.directions[direction]); | |
++longueur; | |
} | |
sens[direction % 4] += longueur; | |
} | |
} | |
void ponderer_colonnes(void) { | |
for(int i_joueur = 0 ; i_joueur < NOMBRE_JOUEURS ; i_joueur++) { | |
joueurs[i_joueur].index_max = LARGEUR_DAMIER / 2; | |
joueurs[i_joueur].poids_max = -1; | |
for(int i_colonne = 0 ; i_colonne < LARGEUR_DAMIER ; i_colonne++) { | |
joueurs[i_joueur].poids_colonne[i_colonne] = -1; | |
if(damier[i_colonne].contenu != CASE_VIDE) continue; | |
faire_tomber_curseur_jusque_case_vide(i_colonne); | |
longueur_suite(&joueurs[i_joueur], joueurs[i_joueur].tous_les_poids_colonne[i_colonne]); | |
joueurs[i_joueur].poids_colonne[i_colonne] = max_eq( | |
&joueurs[i_joueur].tous_les_poids_colonne[i_colonne][0], | |
&joueurs[i_joueur].tous_les_poids_colonne[i_colonne][3] | |
).value; | |
// curseur.soi->contenu = joueurs[i_joueur].symbole; | |
// | |
// curseur.soi->contenu = CASE_VIDE; | |
} | |
joueurs[i_joueur].index_max = max_eq( | |
&joueurs[i_joueur].poids_colonne[0], | |
&joueurs[i_joueur].poids_colonne[LARGEUR_DAMIER - 1] | |
).index; | |
joueurs[i_joueur].poids_max = joueurs[i_joueur].poids_colonne[joueurs[i_joueur].index_max]; | |
} | |
} | |
long int choix_ia() { | |
long int choix = joueurs[joueur_actif_i].index_max; | |
for (int i = 0; i < NOMBRE_JOUEURS; ++i) { | |
if (i == joueur_actif_i) continue; | |
if (joueurs[i].poids_max > joueurs[joueur_actif_i].poids_max || joueurs[i].poids_max == LONGUEUR_VICTOIRE) | |
choix = joueurs[i].index_max; /* On contre l'ennemi */ | |
} | |
return choix; | |
} | |
int main(int argc, char * argv[]) { | |
char char_rec = '\0'; | |
char * string_rec[10]; | |
long colonne_jouee; | |
int jeu_fini_egalite = 0; | |
time_t the_time = time(NULL); | |
if (the_time == -1) { | |
puts("Cannot initialize the time"); | |
return EXIT_FAILURE; | |
} | |
srand((unsigned int) the_time); | |
joueurs[0].symbole = CASE_JOUEUR_1; | |
joueurs[1].symbole = CASE_JOUEUR_2; | |
for (int i = 0 ; i < LONGUEUR_DAMIER ; i++) { | |
damier[i].contenu = CASE_VIDE; | |
damier[i].index = i; | |
damier[i].colonne = i % LARGEUR_DAMIER; | |
damier[i].ligne = i / LARGEUR_DAMIER; | |
} | |
afficher_damier(); | |
for (int i = 0 ; i < NOMBRE_JOUEURS ; ++i) { | |
do { | |
printf("\nJoueur %d humain ou ordinateur ? (H/O)\n> ", i + 1); | |
scanf(" %c%*[^\n]", &char_rec); | |
if (tolower(char_rec) == 'h') { | |
joueurs[i].humain = '\1'; | |
} | |
} while (tolower(char_rec) != 'h' && tolower(char_rec) != 'o'); | |
} | |
while(1) { | |
ponderer_colonnes(); | |
afficher_ponderations(); | |
if (joueurs[joueur_actif_i].humain) { | |
printf( | |
"Au joueur %d (%c) de jouer (un chiffre entre 1 et %d)\n> ", | |
(joueur_actif_i + 1), | |
joueurs[joueur_actif_i].symbole, | |
LARGEUR_DAMIER | |
); | |
while (1) { | |
scanf(" %9s%*[^\n]", &string_rec); | |
colonne_jouee = strtol((const char *) &string_rec, NULL, 10) - 1; | |
if (colonne_jouee >= 0 && colonne_jouee < LARGEUR_DAMIER) { | |
if(damier[colonne_jouee].contenu == CASE_VIDE) { | |
printf("Le joueur %d (%c) joue à la colonne %ld\n", | |
(joueur_actif_i + 1), | |
joueurs[joueur_actif_i].symbole, | |
colonne_jouee + 1 | |
); | |
break; | |
} | |
else { | |
puts("Colonne remplie, veuillez en choisir une autre."); | |
} | |
} else { | |
puts("Chiffre invalide."); | |
} | |
} | |
} else { | |
colonne_jouee = choix_ia(); | |
printf("L'ordinateur joue pour le joueur %d (%c) à la colonne %ld\n", | |
(joueur_actif_i + 1), | |
joueurs[joueur_actif_i].symbole, | |
colonne_jouee + 1 | |
); | |
fflush(stdin); | |
getchar(); | |
} | |
faire_tomber_curseur_jusque_case_vide(colonne_jouee); | |
curseur.soi->contenu = joueurs[joueur_actif_i].symbole; | |
afficher_damier(); | |
if(joueurs[joueur_actif_i].poids_colonne[colonne_jouee] >= LONGUEUR_VICTOIRE) { | |
break; | |
} | |
jeu_fini_egalite = 1; | |
for (int i = 0; i < LARGEUR_DAMIER; ++i) { | |
if(damier[i].contenu == CASE_VIDE) { | |
jeu_fini_egalite = 0; | |
break; | |
} | |
} | |
if (jeu_fini_egalite) { | |
joueur_actif_i = -1; | |
break; | |
} | |
joueur_actif_i = (joueur_actif_i + 1) % NOMBRE_JOUEURS; | |
} | |
if (joueur_actif_i >= 0) | |
printf("Le joueur %d (%c) a gagné", joueur_actif_i, joueurs[joueur_actif_i].symbole); | |
else | |
puts("Egalité !"); | |
fflush(stdin); | |
getchar(); | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment