Salut à tous.
Tout d’abord, je souhaite dire un grand merci aux rédacteurs du cours de programmation en c, je l’ai trouvé très clair, du moins pour l’instant, je n’ai pas encore abordé la partie avancée.
Je me suis donc adonné au TP du puissance 4 (pas encore d’ia), bon j’avoue avoir un peu regardé la fonction pour vider le tampon et m’en servir dans mon code, mais autrement je suis parti de mon propre code, et j’aimerais avoir des avis sur ce qui n’est pas trop correct, incorrect, ce qui pourrait être amélioré, etc.
Mon code se situe ici (il y a 600 lignes, je ne sais pas si je peux le mettre sur le forum):
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
enum {QUITTER, CONTINUER};
typedef struct
{
char *grille;
const unsigned largeur;
const unsigned hauteur;
const unsigned nbCases;
const unsigned dimCase;
} Grille;
typedef struct
{
char *numeros;
char *ligne;
char *ligneVide;
char *casePion;
} ElementsGrille;
typedef struct
{
char *nom;
char pion;
} Joueur;
typedef struct
{
unsigned id;
unsigned lignes;
unsigned colonnes;
unsigned alignement;
unsigned dimCase;
} Jeux;
const int DIRECTIONS[4][2][2] = {
{
{-1, 0}, {1, 0}, // o <- -> e
},
{
{0, -1}, {0, 1}, // n <- -> s
},
{
{-1, -1}, {1, 1}, // no <- -> se
},
{
{1, -1},{-1, 1}, // ne <- -> so
},
};
const Jeux JEUX[] = {
{1, 6, 7, 4, 3},
{2, 8, 12, 5, 1},
{3, 3, 3, 3, 3},
};
const int NB_JEUX = 3;
int intlen(int n);
void convertirNombre(char *chaine, unsigned nombre, unsigned longueurNombre);
int intervalle(int v, int vmin, int vmax);
void viderTampon();
void recupererSaisieColonne(unsigned *colonne, const unsigned CMIN, const unsigned CMAX);
int insererPion(Grille *grille, unsigned colonne, const char pion);
unsigned compterPions(
Grille *grille,
char pion,
unsigned ligne,
unsigned colonne,
int pasH,
int pasV
);
unsigned alignement(Grille *grille, unsigned ligne, unsigned colonne, unsigned suite);
void initialiserGrille(Grille *grille);
unsigned initialiserElementsGrille(Grille *grille, ElementsGrille *elg);
void libererElementsGrille(ElementsGrille *elg);
void afficherGrille(Grille *grille, ElementsGrille *elg);
void genererNumerosColonnes(
char *nums,
unsigned nb_colonnes,
unsigned largeurColonne
);
void genererLigneSeparation(char *ligne, unsigned nb_colonnes, unsigned nbsep);
void genererLigneVide(char *ligne, unsigned nb_colonnes, unsigned largeur_colonne);
void genererCasePion(char *casePion, unsigned largeurColonne);
void selectionIdJeu(unsigned *selection);
unsigned jouer(const Joueur *joueurs);
unsigned rejouer();
int main(int argc, char *argv[])
{
printf(
"\n*************************************"
"\n***** ****"
"\n*** JEU DES PIONS ALIGNES ***"
"\n***** *****"
"\n*************************************\n\n"
);
printf(
"INFORMATION:\nVous pouvez quitter le jeu en cours "
"en saisissant 0 (zero) comme n° de colonne.\n\n"
);
unsigned statut;
const char PIONS[] = {'X', 'O'};
const Joueur joueurs[2] = {
{"Joueur I", PIONS[0]},
{"Joueur II", PIONS[1]}
};
while(1)
{
statut = jouer(joueurs);
if(statut == QUITTER)
break;
}
printf("\nAU REVOIR !\n\n");
return 0;
}
int intlen(int n)
{
int i = 1;
while(n >= 10)
{
n /= 10;
i++;
}
return i;
}
void convertirNombre(char *chaine, unsigned nombre, unsigned longueurNombre)
{
unsigned i, p, n = 0;
for(i=longueurNombre; i>0; i--)
{
p = pow(10, i-1);
chaine[n++] = '0' + (nombre / p);
nombre -= p * (nombre / p);
}
chaine[n] = '\0';
}
void viderTampon()
{
char c = NULL;
while(c != '\n')
{
scanf("%c", &c);
}
}
unsigned compterPions(
Grille *grille,
char pion,
unsigned ligne,
unsigned colonne,
int pasH,
int pasV)
{
unsigned i = 0;
int l = ligne, c = colonne;
int bh = pasH == 1 ? grille->largeur : -1;
int bv = pasV == 1 ? grille->hauteur : -1;
while(1)
{
l += pasV;
c += pasH;
if( l == bv ||
c == bh ||
*(grille->grille + (c + l * grille->largeur)) != pion
)
break;
i++;
}
return i;
}
unsigned alignement(Grille *grille, unsigned ligne, unsigned colonne, unsigned suite)
{
unsigned i, j, aligne;
suite--; // - case de référence
char pion = *(grille->grille + (colonne + ligne * grille->largeur));
for(i=0; i<4; i++)
{
aligne = 0;
for(j=0; j<2; j++)
{
aligne += compterPions(
grille,
pion,
ligne,
colonne,
DIRECTIONS[i][j][0],
DIRECTIONS[i][j][1]
);
if(aligne >= suite)
return 1;
}
}
return 0;
}
unsigned jouer(const Joueur *joueurs)
{
unsigned idJeu, indJeu, gagnant = 0, statut = CONTINUER;
selectionIdJeu(&idJeu);
indJeu = idJeu - 1;
Grille grille = {
NULL,
JEUX[indJeu].colonnes,
JEUX[indJeu].lignes,
JEUX[indJeu].lignes * JEUX[indJeu].colonnes,
JEUX[indJeu].dimCase
};
grille.grille = malloc(sizeof(char) * grille.nbCases);
if(grille.grille == NULL)
return EXIT_FAILURE;
initialiserGrille(&grille);
ElementsGrille elementsGrille = {NULL, NULL, NULL, NULL};
if(!initialiserElementsGrille(&grille, &elementsGrille))
{
free(grille.grille);
return EXIT_FAILURE;
}
const unsigned CMIN = 0, CMAX = grille.largeur;
unsigned colonne, tour = 0;
int ligne;
while(tour < grille.nbCases)
{
afficherGrille(&grille, &elementsGrille);
printf("\n%s : ", joueurs[tour % 2].nom);
while(1)
{
recupererSaisieColonne(&colonne, CMIN, CMAX);
if(!colonne)
{
statut = QUITTER;
break;
}
ligne = insererPion(&grille, colonne-1, joueurs[tour % 2].pion);
if(ligne != -1)
{
break;
}
else
{
printf("\n*** Cette colonne est pleine ! ***\n");
}
}
if(statut == QUITTER)
break;
if(alignement(&grille, ligne, colonne-1, JEUX[indJeu].alignement))
{
gagnant = 1;
break;
}
tour++;
}
if(statut != QUITTER)
{
afficherGrille(&grille, &elementsGrille);
if(gagnant)
printf("\n\n%s a gagné !\n\n", joueurs[tour % 2].nom);
else
printf("\n\nPartie nulle !\n\n");
statut = rejouer();
}
free(grille.grille);
libererElementsGrille(&elementsGrille);
return statut;
}
unsigned rejouer()
{
unsigned r, i;
while(1)
{
printf(
"Souhaitez-vous faire une autre partie ?\n"
"1 - Oui\n"
"0 - Non\n"
);
r = scanf("%d", &i);
if(!r || (i != 0 && i != 1))
{
printf("\n*** Choix invalide ! ***\n\n");
}
else
{
break;
}
viderTampon();
}
return i == 0 ? QUITTER : CONTINUER;
}
void selectionIdJeu(unsigned *selection)
{
unsigned i, r;
while(1)
{
printf("\nChoisissez le type de jeu :\n");
for(i=0; i<NB_JEUX; i++)
{
printf(
"%d - %d lignes x %d colonnes, %d pions à aligner.\n",
JEUX[i].id,
JEUX[i].lignes,
JEUX[i].colonnes,
JEUX[i].alignement
);
}
r = scanf("%d", selection);
if(!r)
{
printf("\n*** Veuillez choisir un n° de jeu. ***\n\n");
}
else if(!intervalle(*selection, 1, NB_JEUX))
{
printf("\n*** Ce numéro de jeu est invalide. ***\n\n");
}
else
{
break;
}
viderTampon();
}
}
void initialiserGrille(Grille *grille)
{
unsigned i;
for(i=0; i<grille->nbCases; i++)
{
*(grille->grille + i) = ' ';
}
}
void genererNumerosColonnes(
char *nums,
unsigned nb_colonnes,
unsigned largeurColonne)
{
int i, j, k, ln, p, s, c = 0;
char *pn = NULL;
pn = malloc(sizeof(char) * ((intlen(nb_colonnes) + 1)));
nums[c++] = ' ';
for(i=1; i<=nb_colonnes; i++)
{
ln = intlen(i);
convertirNombre(pn, i, ln);
p = (largeurColonne - ln) / 2;
s = largeurColonne - ln - p + 1;
for(j=0; j<p; j++)
nums[c++] = ' ';
for(k=0; k<ln; k++)
nums[c++] = pn[k];
for(j=0; j<s; j++)
nums[c++] = ' ';
}
nums[c] = '\0';
free(pn);
}
void genererLigneSeparation(char *ligne, unsigned nb_colonnes, unsigned nbsep)
{
unsigned i, j=0, s;
for(i=0; i<nb_colonnes; i++)
{
ligne[j++] = '+';
for(s=0; s<nbsep; s++)
ligne[j++] = '-';
}
ligne[j++] = '+';
ligne[j] = '\0';
}
void genererLigneVide(char *ligne, unsigned nb_colonnes, unsigned largeur_colonne)
{
unsigned i, j, n = 0;
for(i=0; i<nb_colonnes; i++)
{
ligne[n++] = '|';
for(j=0; j<largeur_colonne; j++)
{
ligne[n++] = ' ';
}
}
ligne[n++] = '|';
ligne[n] = '\0';
}
void genererCasePion(char *casePion, unsigned largeurColonne)
{
unsigned i, p, s, n = 0;
largeurColonne--;
p = largeurColonne / 2;
s = largeurColonne - p;
for(i=0; i<p; i++)
casePion[n++] = ' ';
casePion[n++] = '%';
casePion[n++] = 'c';
for(i=0; i<s; i++)
casePion[n++] = ' ';
casePion[n] = '\0';
}
void afficherGrille(Grille *grille, ElementsGrille *elg)
{
unsigned i, j, t, tc;
tc = grille->dimCase / 2;
printf("\n%s\n", elg->numeros);
for(i=0; i<grille->hauteur; i++)
{
printf("%s\n", elg->ligne);
for(t=0; t<tc; t++)
printf("%s\n", elg->ligneVide);
for(j=0; j<grille->largeur; j++)
{
printf("|");
printf(
elg->casePion,
*(grille->grille + (j + i * (grille->largeur)))
);
}
printf("|\n");
for(t=0; t<tc; t++)
printf("%s\n", elg->ligneVide);
}
printf("%s\n", elg->ligne);
printf("%s\n", elg->numeros);
}
int insererPion(Grille *grille, unsigned colonne, const char pion)
{
int i = colonne + (grille->hauteur - 1) * grille->largeur;
for(i=i; i>-1; i-=grille->largeur)
{
if(*(grille->grille + i) == ' ')
{
*(grille->grille + i) = pion;
return (i - colonne) / grille->largeur;
}
}
return -1;
}
int intervalle(int v, int vmin, int vmax)
{
return v >= vmin && v <= vmax;
}
void recupererSaisieColonne(unsigned *colonne, const unsigned CMIN, const unsigned CMAX)
{
unsigned r;
while(1)
{
r = scanf("%d", colonne);
if(!r)
{
printf("\n*** Veuillez entrer un nombre ! ***\n");
}
else if(!intervalle(*colonne, CMIN, CMAX))
{
printf("\n*** Veuillez entrer un n° de colonne valide ! ***\n");
}
else
{
break;
}
viderTampon();
}
viderTampon();
}
void libererElementsGrille(ElementsGrille *elg)
{
free(elg->numeros);
free(elg->ligne);
free(elg->ligneVide);
free(elg->casePion);
}
unsigned initialiserElementsGrille(Grille *grille, ElementsGrille *elg)
{
unsigned tc = (grille->dimCase * 2 + 1) * grille->largeur + 2;
elg->numeros = malloc(sizeof(char) * tc);
elg->ligne = malloc(sizeof(char) * tc);
elg->ligneVide = malloc(sizeof(char) * tc);
elg->casePion = malloc(sizeof(char) * grille->dimCase * 2 + 1);
if( elg->numeros == NULL ||
elg->ligne == NULL ||
elg->ligneVide == NULL ||
elg->casePion == NULL )
{
libererElementsGrille(elg);
return 0;
}
genererNumerosColonnes(elg->numeros, grille->largeur, grille->dimCase * 2);
genererLigneSeparation(elg->ligne, grille->largeur, grille->dimCase * 2);
genererLigneVide(elg->ligneVide, grille->largeur, grille->dimCase * 2);
genererCasePion(elg->casePion, grille->dimCase * 2);
return 1;
}
Merci d’avance à ceux qui essaieront d’analyser mon code.
Question subsidiaire : Si j’aperçois des fautes d’orthographe dans un cours, à qui dois-je le signaler ?