Skip to content

Instantly share code, notes, and snippets.

@Meithal
Created July 15, 2018 03:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Meithal/476894ff04ba51e72455a9fa33e015fe to your computer and use it in GitHub Desktop.
Save Meithal/476894ff04ba51e72455a9fa33e015fe to your computer and use it in GitHub Desktop.
p4
#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