Ah dommage je modifie donc pour avoir un code portable , je pensais qu'il était je n'ai pourtant utilise aucun "appel du système "?
La table ASCII n'est pas universelle?
Rien de bien compliqué dans cet exercice, il suffisait simplement de faire comme si on jouait sur papier.
Le plus dur est sûrement la fonction qui teste quel joueur a gagné. Pour cela il y avait plusieurs options :
- Si vous partez sur un morpion 3x3 (taille fixe), vous pouvez faire un gros 'if' qui teste toutes les positions. Pas grand chose, il y a 8 positions à tester.
- Si vous partez sur un morpion NxN (taille variable), il n'y a rien de bien compliqué non plus. Pour éviter de tester toute la grille, on ne testera que le dernier coup joué. Pour ça, il suffit de partir du dernier coup joué et de teste la colonne, la ligne et les 2 diagonales à partir du coup. Tous les autres coups ne nous intéressent pas, ils ne changent pas !
Vous pouvez le faire de plusieurs manières, mais toutes se ressemblent plus ou moins. La méthode proposée dans mon code est simplement de se dire qu'on a 4 directions à tester (1 ligne, 1 colonne, 2 diagonales) et de compter le nombre de pions alignés. On teste également les directions 'inverse' ('derrière' le pion) et on ajoute ce compte aux directions 'normales'. Si le nombre de pions alignés trouvés sont supérieurs ou égaux au nombre qu'il faudrait aligner, c'est qu'on a gagné, autrement on teste les autres directions.
Voilà le code, je n'ai pas mis de commentaires, il me paraît assez clair, mais si vous voyez un endroit qui vous paraît obscur, dîtes le moi :
#include <ctype.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
enum {
TAB_H = 3, /* Hauteur */
TAB_W = 3, /* Largeur */
TAB_T = TAB_H * TAB_W, /* Nbre total de cases */
NBR_P = 3 /* Nbre de pions à aligner */
};
enum {
VIDE = 0,
J1 = 1,
J2 = 2
};
typedef struct Coord_ {
int x;
int y;
} Coord;
void viderStdin(void) {
int c;
while ((c = getchar()) != '\n' && c != EOF)
;
}
int testerCoup(int * tab, Coord * c) {
if (c->x < 0 || c->x >= TAB_W || c->y < 0 || c->y >= TAB_H ||
tab[c->y * TAB_W + c->x] != VIDE)
return 0;
else
return 1;
}
int saisieCoord(int * tab, Coord * c) {
do {
printf("Entrez les coordonees (x y) : ");
scanf("%d%d", &c->x, &c->y);
viderStdin();
c->x--;
c->y--;
} while (!testerCoup(tab, c));
return 0;
}
int jouerCoup(int * tab, Coord * c, int joueur) {
tab[c->y * TAB_W + c->x] = joueur;
return 0;
}
void affiche(int * tab) {
char * s = ".XO";
int i;
for (i = 0; i < TAB_T; i++) {
if (i && i % TAB_H == 0)
puts("");
putchar(s[tab[i]]);
}
puts("");
}
int compterDir(int * tab, Coord * c, int x, int y, int joueur) {
int cnt, i, j;
cnt = 0;
i = c->x + x;
j = c->y + y;
while (i >= 0 && i < TAB_W && j >= 0 && j < TAB_H &&
tab[j * TAB_W + i] == joueur) {
cnt++;
j += y;
i += x;
}
return cnt;
}
int estCoupGagnant(int * tab, Coord * c, int joueur) {
Coord dir[4] = {
{ 0, 1 }, { 1, 0 },
{ 1, 1 }, { 1, -1 }
};
int cnt, i;
for (i = 0; i < 4; i++) {
cnt = compterDir(tab, c, dir[i].x, dir[i].y, joueur);
cnt += compterDir(tab, c, -dir[i].x, -dir[i].y, joueur);
if (cnt + 1 >= NBR_P)
return 1;
}
return 0;
}
int estGagnant(int ret, int joueur, int pce) {
if (ret)
printf("Joueur %d gagne !\n", joueur);
else if (pce >= TAB_T)
printf("Match nul !\n");
else
return 0;
return 1;
}
void jouer(int joueur) {
int tab[TAB_T] = { 0 };
int done, pce, ret;
Coord c;
printf("Joueur %d commence !\n\n", joueur);
affiche(tab);
pce = 0;
done = 0;
while (!done) {
saisieCoord(tab, &c);
jouerCoup(tab, &c, joueur);
pce++;
ret = estCoupGagnant(tab, &c, joueur);
done = estGagnant(ret, joueur, pce);
affiche(tab);
joueur = 3 - joueur;
}
}
int rejouer(void) {
int c;
do {
printf("Voulez-vous rejouer (o)ui/(n)on ? ");
c = getchar();
viderStdin();
c = toupper(c);
} while (c != 'N' && c != 'O');
return c == 'O';
}
int init(void) {
srand(time(NULL));
return 0;
}
int main(void) {
int joueur;
init();
joueur = rand() % 2 + 1;
do {
jouer(joueur);
joueur = 3 - joueur;
} while (rejouer());
return EXIT_SUCCESS;
}
J'ai modifié compterDir parce que c'est vrai qu'elle était pas très lisible. :-)
Edit: Modif mineure (nom de variable).
Je rêve ou tu as un trait obsessionnel au niveau des fonctions (obsession des fonctions) ?
int init(void) { // C'est exagérer non ?
srand(time(NULL));
return 0;
}
Et aussi :
int jouerCoup(int * tab, Coord * c, int joueur) {
tab[c->y * TAB_W + c->x] = joueur; // Une seule ligne. -_-"
return 0;
}
Sinon j'aime bien ta fonction affiche (c'est qui ces types qui veulent pas faire comme tout le monde et qui fond des fonctions originales pour afficher un tableau). Et j'ai pas le courage de me lancer dans ta fonction testerGrille().
Edit :
Ah aussi :
enum {
VIDE = 0,
J1 = 1,
J2 = 2
};
Ce ne sont pas les valeurs qui sont attribuées automatiquement ? Et d'ailleurs tu n'as pas vraiment besoin de leur attribuer de valeur non ? Dernière chose, ni J1 ni J2 n'est utilisée.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles- ♡ Copying is an act of love.
Je rêve ou tu as un trait obsessionnel au niveau des fonctions (obsession des fonctions) ?
Faire des fonctions, même petites, c'est considéré comme une bonne pratique.
Là tu ne vois pas l'intérêt de la fonction init, ok, mais lorsque le programme va évoluer ça demandera surement moins de travail que tout en dur dans le main.
Citation : @che
(c'est qui ces types qui veulent pas faire comme tout le monde et qui fond des fonctions originales pour afficher un tableau).
Marrant ce point de vue. Mais ça n'a rien d'original, c'est seulement sale.
Non, même pas, je veux bien pour compteDir, mais la fonction d'affichage est très classique!
Pour la série d'enum suivante je suis d'accord.
Pour finir, c'est dur de pondre un code qui satisfait tout le monde, hein!
Exagéré ? non.
Pour la fonction init, certes elle parait seule et isolée mais si tu regardes bien, si je passe mon jeu en SDL, bah ma fonction est déjà prête.
Pour la fonction jouerCoup, bah, simplement que c'est plus lisible de lire ça que une affectation de tableau foireuse. Là elle n'est utilisée qu'une seule fois, mais si tu l'utilises 50 fois dans ton programme ? tu la modifieras 50 fois dans ton programme au risque d'en oublier...
Citation : @che
Et j'ai pas le courage de me lancer dans ta fonction testerGrille().
Bah, ya rien de compliqué la dedans, il suffit juste de réfléchir un peu...
Les valeurs de l'enum sont attribuées automatiquement, simplement je n'avais pas utilisé ces valeurs là au départ, je les ai donc laissées. Les valeurs de l'enum ne sont pas utilisées non plus, mais encore une fois c'est pour l'évolution du programme, pour l'IA par exemple (que tu n'as pas faite).
Comme je l'ai dis, il faut essayer de faire un programme évolutif, regardes mon programme console et SDL, tu verras que le nombre de fonctions qui ont été touchées par le passage console->SDL est très faible (genre 2 ou 3 fonctions pas plus).
GurneyH > Sale pour mon affichage ? mouais bof, je préfère ça à une série de if...else et cie.
Les valeurs de l'enum sont attribuées automatiquement, simplement je n'avais pas utilisé ces valeurs là au départ, je les ai donc laissées. Les valeurs de l'enum ne sont pas utilisées non plus, mais encore une fois c'est pour l'évolution du programme, pour l'IA par exemple (que tu n'as pas faite)
Hum qu'es-ce que tu sous entends par cette petite phrase ?
Citation : Pouet_forever
Comme je l'ai dis, il faut essayer de faire un programme évolutif, regardes mon programme console et SDL, tu verras que le nombre de fonctions qui ont été touchées par le passage console->SDL est très faible (genre 2 ou 3 fonctions pas plus).
C'est vrais. Désolé je compte pas faire l'exo en SDL, je préfère en console.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles- ♡ Copying is an act of love.
J'avais complètement zappé la partie 2 de l'exo... j'édite immédiatement ma signature et je vais me tenté à l'algo min-max ou alpha-beta (promis, pas 50 if/elseif).
J'ai fait un petit code pour ce fameux morpion. Il est fini (presque mais j'expliquerais pourquoi après), et débuggé, reste plus qu'à le critiquer. Je n'ai pas fait d'IA (je ne trouve pas très intéressant de me taper une série de if/else sachant que j'ai déjà subit ça avec un jeu de mastermind).
Je me lancerait dans l'IA avec les algorithmes que tu as cité après en avoir fini avec les différentes tailles de grille, parce que comme qui dirait : chaque chose en son temps quand on est débutant !!
Pourquoi il n'est pas vraiment fini? Parce que ma fonction testWinMoche() est, comme son nom l'indique, moche C'est un truc trivial qui ne fonctionne qu'en 3x3 et qui est justement une série de if toute moche.
Donc sur ce, je vous soumet le code tel quel et je me penche sur une solution qui regardera ligne / colonne / diagonale du dernier coup pour pouvoir jouer sur des 4x4 et 5x5 sans avoir à refaire une fonction encore plus longue.
PS : Pouet Forever, c'est pas contre toi mais j'aime vraiment pas cette indentation, on dirait du Eclipse berk !!
Le code :
main.c :
#include <stdio.h>
#include <stdlib.h>
#include "fct.h"
int main()
{
int win=RIEN, joueurActuel=J1, coup=0, erreur=0;
char grille[NB_CASES]={0};
InitJeu(grille,NB_CASES);
AffGrille(grille,NB_CASES);
while(win==RIEN)
{
/*Récupérer le coup du joueur 1 ou 2*/
printf("Joueur %d : ",joueurActuel);
coup=recupCoup();
/*mettre à jour le tableau*/
if(grille[coup-1]=='.')
grille[coup-1]=(joueurActuel==J1)?'o':'x'; /*Joueur 1 a les 'o' et joueur 2 a les 'x'*/
else
{
printf("Erreur, case deja jouee.\n");
erreur=1;
}
/*Afficher la grille*/
AffGrille(grille,NB_CASES);
/*tester si gagnant : win j1, win j2, nul, continuer à jouer*/
win=testWinMoche(grille,NB_CASES,coup);
annonceWin(win,joueurActuel);
/*Changement de joueur, test si case jouée ou pas*/
if(erreur) /*Si erreur, on recommence*/
{
erreur=0;
}else /*Sinon c'est à l'autre joueur de jouer*/
{
if(joueurActuel==J1)
joueurActuel=J2;
else joueurActuel=J1;
}
}
return 0;
}
fct.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "fct.h"
void InitJeu(char *tab, int tablen)
{
int i=0;
for(i=0;i<tablen;i++)
tab[i]='.';
}
void AffGrille(char *tab, int tablen)
{
int i=0, j=0, casesParLignes=(int)sqrt((double) tablen);
for(i=0;i<casesParLignes;i++)
{
for(j=tablen-((i+1)*casesParLignes);j<(tablen-(i*casesParLignes));j++)
printf("%c",tab[j]);
printf("\n");
}
printf("\n\n");
}
int recupCoup(void)
{
int coup=0;
scanf("%d",&coup);
while(getchar()!='\n');
coup=(coup<=0||coup>NB_CASES)?1:coup; /*sécurité temporaire, une boucle remplacera ça*/
return coup;
}
int testWinMoche(char *tab, int tablen, int dernierCoup)
{
int win=RIEN;
int flag=0, i=0;
/*test lignes - ALGORITHME MOCHE (seulement 9 cases)*/
if(tab[0]!='.')
{
if(tab[1]==tab[0]&&tab[2]==tab[0]) /*ligne du haut*/
win=WIN;
else if(tab[3]==tab[0]&&tab[6]==tab[0]) /*colonne de gauche*/
win=WIN;
}
if(tab[4]!='.')
{
if(tab[3]==tab[4]&&tab[5]==tab[4]) /*ligne du milieu*/
win=WIN;
else if(tab[1]==tab[4]&&tab[7]==tab[4]) /*colonne du milieu*/
win=WIN;
}
if(tab[8]!='.')
{
if(tab[7]==tab[8]&&tab[6]==tab[8]) /*ligne du bas*/
win=WIN;
else if(tab[5]==tab[8]&&tab[2]==tab[8]) /*colonne de droite*/
win=WIN;
}
/*si impair : test diagonales en plus - ALGORITHME MOCHE (seulement 9 cases)*/
if(dernierCoup%2!=0)
{
if(tab[4]!='.')
{
if(tab[0]==tab[4]&&tab[8]==tab[4]) /*diagonale haut-gauche / bas-droite*/
win=WIN;
else if(tab[2]==tab[4]&&tab[6]==tab[4]) /*diagonale haut-droite / bas-gauche*/
win=WIN;
}
}
/*test nulle*/
for(i=0;i<tablen;i++)
{
if(tab[i]!='.')
flag++;
}
if(flag==9)
win=NUL;
return win;
}
void annonceWin(int flag, int joueurActuel)
{
if(flag==WIN)
printf("Bravo, joueur %d a gagne !\n",joueurActuel);
else if(flag==NUL)
printf("Partie nulle !\n");
}
et fct.h :
#include <stdio.h>
#include <stdlib.h>
#define NB_CASES 9
#define J1 1
#define J2 2
#define WIN 15
#define NUL 16
#define RIEN 17
void InitJeu(char *tab, int tablen);
void AffGrille(char *tab, int tablen);
int recupCoup(void);
int testWinMoche(char *tab, int tablen, int dernierCoup);
void annonceWin(int flag, int joueurActuel);
quentin-fait-du-c> Merci pour ta participation.
Si la fonction ne prend aucun argument, il faudrait la déclarer prenant 'void' comme argument (int main(void))
Dans ta fonction AffGrille, tu pourrais éviter l'appel à sqrt et faire soi ta propre fonction sqrt prenant et retournant un int ou soit utiliser le modulo dans ta boucle
Ta boucle est quelque peu curieuse, pourquoi ne pas faire les calculs dans l'indice du tableau directement ? ça rendrait ton code plus clair
Je ne dis rien sur ta fonction recupCoup, tu la modifieras apparemment
Pour ta gestion d'erreur, tu peux faire une fonction ou mettre ça dans une boucle, là c'est un peu bizarre
Je ne dis rien sur ta fonction testWinMoche non plus
Tu pourrais protéger ton header contre les inclusions infinies
Tu n'as pas besoin de stdio.h et stdlib.h dans ton header
Tu n'as pas besoin de stdlib.h dans aucun de tes fichiers
Les valeurs que tu as utilisé pour tes define sont quelque peu curieuses
Ce que je te conseille, c'est d'utiliser des 0,1,2 pour ton tableau (qui correspondent à VIDE, J1, J2) et ne te préocuper des 'o' et cie uniquement dans ta fonction d'affichage. Ca te permettrait de rendre ton code un peu plus clair.
Tu pourrais utiliser des enum pour tes déclarations de constantes (rien ne t'y oblige)
PS : Moi j'aime bien et je m'y suis habitué. Après, chacun à son propre style d'indentation, ce qu'il y a c'est qu'il faut s'y tenir.
Si la fonction ne prend aucun argument, il faudrait la déclarer prenant 'void' comme argument (int main(void))
Ben ça c'est C::B qui me met cette forme automatiquement. Je vais supprimer ça de suite.
Citation : Pouet_forever
Dans ta fonction AffGrille, tu pourrais éviter l'appel à sqrt et faire soi ta propre fonction sqrt prenant et retournant un int ou soit utiliser le modulo dans ta boucle
Ou alors je peux faire comme toi et faire une série de #define qui calculeront les valeurs. Je trouve ça bien plus simple
Citation : Pouet_forever
Ta boucle est quelque peu curieuse, pourquoi ne pas faire les calculs dans l'indice du tableau directement ? ça rendrait ton code plus clair
Euh parce que je ne maitrise pas les trucs de la forme tab[i++]=... et que donc j'ai pas envie de faire d'erreur que je ne saurais pas débugger Pour changer ça, il va me falloir un coup de main !
Citation : Pouet_forever
Pour ta gestion d'erreur, tu peux faire une fonction ou mettre ça dans une boucle, là c'est un peu bizarre
Bonne idée je vais essayer de faire ça dans un fonction En théorie ça devrait pas me poser de problème.
Citation : Pouet_forever
Les valeurs que tu as utilisé pour tes define sont quelque peu curieuses
Ce que je te conseille, c'est d'utiliser des 0,1,2 pour ton tableau (qui correspondent à VIDE, J1, J2) et ne te préocuper des 'o' et cie uniquement dans ta fonction d'affichage. Ca te permettrait de rendre ton code un peu plus clair.
Tu pourrais utiliser des enum pour tes déclarations de constantes (rien ne t'y oblige)
Ben ça c'est des valeurs au pif comme qui dirait Je vais modifier ça. Pour les enum, j'aime pas trop ça les defines permettent de maitriser la valeur et de faire des debuggages (plus) facilement.
Je vais essayer de remplacer tous les caractères dans le code par leur code et de faire vraiment l'interface algo / affichage.
EDIT : Au final, comme c'est déjà débuggé et que ça fonctionne (sauf si j'ai pas tout testé), j'ai remplacé par 2 enum et j'ai pris les dimensions d'un carré par calcul à partir de la taille du coté. Voilà
Me reste plus qu'à faire une fonction testWin -PAS MOCHE-, mais ça c'est un sacré problème.
Je voudrais que la fonction regarde la ligne, la colonne, et la diagonale (le cas échéant) du dernier coup joué pour tester un alignement. Sauf que si je joue sur les cases 1, 4, 7, 8, 9 (du pavé numérique), pas de problème. Pour les autres, il va falloir que je décrémente l'indice à un moment et pour ça, je ne sais pas comment faire. Il me faudrait un algo qui tue !
Un ptit coup de main?
Bonsoir à tous, désolé pour le double post mais je me permet de demander un coup de main.
Suite aux explications de Pouet_forever, j'ai essayé de faire un code avec sa méthode dans mon contexte
J'ai juste pas repris le principe des double boucles, je trouve que c'est plus lisible comme ça. Cette fonction testWin m'aura donné du mal...
Sauf que là, j'ai un sacré problème !
J'ai une des 4 fonctions qui délire (verifHor Ver Diag1 et Diag2), car à part 3 pauvres cases, les coups sont gagnants à chaque fois. Il y a donc un problème d'algo. Moi, ça fait 1h30 que je cherche et je commence a vraiment avoir besoin de ma pause clope :s Je me suis donc décidé à poster ici mon code.
Je ne met que la partie testWin pour ne pas vous surcharger inutilement, ce qu'il y a à savoir :
- ma grille est un grille[GRILLE_H] qui est converti en (x;y) par les deux fonctions XYEnLin() et LinEnXY().
- la fonction renvoie le flag `win' qui vaut RIEN, WIN ou NUL, et une autre fonction agit en conséquence.
voilà le code :
int testWin(int *grille, int dernierCoup)
{
int win=RIEN, flag_hor=RIEN, flag_ver=RIEN, flag_diag1=RIEN,
flag_diag2=RIEN, flag_nul=RIEN;
int x=0, y=0;
/*conversion en coordonnées X Y*/
LinEnXY(&x,&y,dernierCoup-1); /*le -1 est nécessaire pour correspondre
aux indices du tableau*/
/*calcul horizontal*/
flag_hor=verifHor(grille,dernierCoup);
/*calcul vertical*/
flag_ver=verifVer(grille,dernierCoup);
/*diag haut gauche - bas droite*/
if(x==y)
flag_diag1=verifDiag1(grille,dernierCoup);
/*diag haut droite - bas gauche*/
if((x+y)==(GRILLE_H-1))
flag_diag2=verifDiag2(grille,dernierCoup);
flag_nul=testNul(grille);
if((flag_hor==WIN || flag_ver==WIN || flag_diag1==WIN
|| flag_diag2==WIN) && flag_nul==RIEN)
win=WIN;
else if(flag_nul==NUL)
win=NUL;
return win;
}
void LinEnXY(int *x, int *y, int coup)
{
*x=coup%GRILLE_H;
*y=coup/GRILLE_H;
}
int XYEnLin(int x, int y)
{
return (x+(y*GRILLE_H));
}
int verifHor(int *grille, int dernierCoup)
{
int win=RIEN;
int i=0, ligne=0, x=0, y=0;
LinEnXY(&x,&y,dernierCoup);
for(i=0;i<GRILLE_H;i++)
{
if(grille[XYEnLin(i,y)]==grille[XYEnLin(x,y)])
ligne++;
}
if(ligne==GRILLE_H)
win=WIN;
return win;
}
int verifVer(int *grille, int dernierCoup)
{
int win=RIEN;
int i=0, ligne=0, x=0, y=0;
LinEnXY(&x,&y,dernierCoup);
for(i=0;i<GRILLE_H;i++)
{
if(grille[XYEnLin(x,i)]==grille[XYEnLin(x,y)])
ligne++;
}
if(ligne==GRILLE_H)
win=WIN;
return win;
}
int verifDiag1(int *grille, int dernierCoup)
{
int win=RIEN;
int i=0, ligne=0, x=0, y=0;
LinEnXY(&x,&y,dernierCoup);
for(i=0;i<GRILLE_H;i++)
{
if(grille[XYEnLin(i,i)]==grille[XYEnLin(x,y)])
ligne++;
}
if(ligne==GRILLE_H)
win=WIN;
return win;
}
int verifDiag2(int *grille, int dernierCoup)
{
int win=RIEN;
int i=0, ligne=0, x=0, y=0;
LinEnXY(&x,&y,dernierCoup);
for(i=0;i<GRILLE_H;i++)
{
if(grille[XYEnLin(GRILLE_H-i-1,i)]==grille[XYEnLin(x,y)])
ligne++;
}
if(ligne==GRILLE_H)
win=WIN;
return win;
}
int testNul(int *grille)
{
int i=0;
for(i=0;i<NB_CASES;i++)
{
if(grille[i]==VIDE)
return RIEN;
}
return NUL;
}
Si il manque des informations, j'éditerais à votre demande. Si l'erreur est trop bête, pardonnez-moi à l'avance
Merci à vous
Bonjour, tout le monde!
Je suis débutant, et du coup, je pense avoir fait une faute dans mon code, mais je ne vois pas laquelle... En effet, , d'un coup à l'autre, la grille ne se modifie pas!
Alors, si quelqu'un avait une idée...
voilà mes trois fichiers:
le main:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
#include <math.h>
#include "fonction.h"
#define NOMBRE_DE_POINTS 9
int main()
{
int continuer=1;
while (continuer)
{
int quelJoueur=0, i=0, choixCase=0;
const int MAX=2, MIN=1;
int quelsPointsOntEteMis[NOMBRE_DE_POINTS]={0};//tableau pour savoir qui a joué quoi
srand(time(NULL));
quelJoueur=(rand()%(MAX - MIN + 1)) + MIN;
printf("\tBienvenue dans le jeu de Morpion!\n\t\t*** par Clement ***\n\n\n");
i=0;
do
{
i++;
jouer (&quelJoueur);
affichage(quelsPointsOntEteMis);
choixCase=saisie();
if (testerCoup(choixCase, quelsPointsOntEteMis))
{
jouerCoup(&quelsPointsOntEteMis[NOMBRE_DE_POINTS], choixCase, quelJoueur);// à définir dans fonction.c
}
else
{
int j=0;
while (j==0)
{
printf ("\n\nCette selection n'est pas valide, veuillez recommencer.\n\n");
choixCase=saisie();
j=testerCoup(choixCase, quelsPointsOntEteMis);
printf("%d", j);//probleme, il ne le fait pas
}
jouerCoup(quelsPointsOntEteMis[NOMBRE_DE_POINTS], choixCase, quelJoueur);
}
printf("%d", i);
}while (i<NOMBRE_DE_POINTS && !testerGagnant(quelsPointsOntEteMis));
if (testerGagnant(quelsPointsOntEteMis)==1)
printf("\n\nBravo, joueur %d, vous avez gagne!!!", quelJoueur);
else
printf("\n\nEGALITE");
printf("\n\nVoulez-vous recommencer?\n\n1 oui\n2 non\n");
scanf("%d", &continuer);
}
return 0;
}
le .c annexe:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
#include <math.h>
#include "fonction.h"
#define NOMBRE_DE_POINTS 9
void jouer(int *quelJoueur)
{
*quelJoueur=3-*quelJoueur;
printf("\n\nC'est a joueur %d de jouer\n\n", *quelJoueur);
}
void affichage(int quelsPointsOntEteMis[])
{
int i=0;
int racine=0;
for (i=0; i<NOMBRE_DE_POINTS; i++)
{
if (quelsPointsOntEteMis[i]==0)
printf(". ");
else if (quelsPointsOntEteMis[i]==1)
printf("X ");
else if (quelsPointsOntEteMis[i]==2)
printf("O ");
else
printf("erreur d'affichage");
racine=sqrt(NOMBRE_DE_POINTS);
if ((i+1)%racine==0)
printf("\n");
}
}
int saisie()
{
int choixCase=0;
printf("\nPour jouer, veuillez entrer un nombre entier naturel entre 1 et 9 inclus. Celui-ci correspodra a une case de la grille ; il vous suffit de compter les points de gauche a droite :");
scanf ("%d", &choixCase);
return choixCase;
}
int testerCoup(int choixCase, int quelsPointsOntEteMis[])
{
int i;
if (quelsPointsOntEteMis[choixCase]==0 && choixCase<=NOMBRE_DE_POINTS && choixCase > 0)
i=1;
else
i=0;
return i;
}
void jouerCoup(int quelsPointsOntEteMis[], int choixCase, int quelJoueur)
{
quelsPointsOntEteMis[choixCase]=quelJoueur;
}
int testerGagnant(int quelsPointsOntEteMis[])
{
int resultat=0;
if (quelsPointsOntEteMis[0]==1 && quelsPointsOntEteMis[1]==1 && quelsPointsOntEteMis[2]==1)
resultat=1;
if (quelsPointsOntEteMis[3]==1 && quelsPointsOntEteMis[4]==1 && quelsPointsOntEteMis[5]==1)
resultat=1;
if (quelsPointsOntEteMis[6]==1 && quelsPointsOntEteMis[7]==1 && quelsPointsOntEteMis[8]==1)
resultat=1;
if (quelsPointsOntEteMis[0]==1 && quelsPointsOntEteMis[4]==1 && quelsPointsOntEteMis[8]==1)
resultat=1;
if (quelsPointsOntEteMis[2]==1 && quelsPointsOntEteMis[4]==1 && quelsPointsOntEteMis[6]==1)
resultat=1;
if (quelsPointsOntEteMis[0]==2 && quelsPointsOntEteMis[1]==2 && quelsPointsOntEteMis[2]==2)
resultat=1;
if (quelsPointsOntEteMis[3]==2 && quelsPointsOntEteMis[4]==2 && quelsPointsOntEteMis[5]==2)
resultat=1;
if (quelsPointsOntEteMis[6]==2 && quelsPointsOntEteMis[7]==2 && quelsPointsOntEteMis[8]==2)
resultat=1;
if (quelsPointsOntEteMis[0]==2 && quelsPointsOntEteMis[4]==2 && quelsPointsOntEteMis[8]==2)
resultat=1;
if (quelsPointsOntEteMis[2]==2 && quelsPointsOntEteMis[4]==2 && quelsPointsOntEteMis[6]==2)
resultat=1;
else
resultat=0;
return resultat;
}
et le haeder:
#define NOMBRE_DE_POINTS 9
void jouer(int* quelJoueur);
void affichage(int quelsPointsOntEteMis[]);
int saisie();
int testerCoup(int choixCase, int quelsPointsOntEteMis[]);
void jouerCoup(int quelsPointsOntEteMis[], int choixCase, int quelJoueur);
int testerGagnant(int quelsPointsOntEteMis[]);
Capricornus > Ton erreur doit être au niveau de la ligne 45 du fichier main.c (ton appel de fonction est faux).
Quelques remarques rapides :
Tu déclares plusieurs fois NOMBRE_DE_POINTS
Tu ne protèges pas ton header contre l'inclusion infinie
Tu appelles srand plusieurs fois dans ton programme (dans la boucle principale), il faudrait l'appeler qu'une seule fois
quelJoueur=(rand()%(MAX - MIN + 1)) + MIN; >> A vrai dire, un simple rand()%2 + 1 suffit pas besoin de faire compliqué !
Dans ta fonction 'jouer' tu modifies le joueur et tu affiches le joueur, ce n'est pas trop ce qu'on attendrait de cette fonction.
L'utilisation de racine=sqrt(NOMBRE_DE_POINTS); est couteuse et inutile, il serait plus judicieux de déclarer une variable qui contient le nombre de lignes/colonnes
Les fonctions qui ne prennent pas de paramètres devraient avoir 'void' (ex. : int main(void))
Dans 'testerCoup' tu fais : if (quelsPointsOntEteMis[choixCase]==0 && choixCase<=NOMBRE_DE_POINTS && choixCase > 0) tu devrais faire l'inverse, là tu testes la case et ensuite si tu es dans les bornes, il faudrait d'abord tester les bornes et ensuite vérifier la grille !
Si l'utilisateur entre une entrée invalide, tu réécris quelque chose que tu as déjà écrit dans la fonction, tu peux simplifier !
Le 'else' dans ta fonction testerGagnant (vers la fin) ne sert à rien. Je pense qu'il ne fait pas non plus ce que tu penses (il est 'valide' qu'avec le dernier if et non tous les autres)
Dans l'ensemble c'est pas trop mal.
LeBri@n > Dans ta fonction 'jouer', tu fais un tableau de TAILLE_PLATEAU+1 et tu l'initialises avec une chaîne, mais qu'est-ce qui se passe si je change la valeur de TAILLE_PLATEAU ?
Dans ta fonction 'testerCoup' tu ne testes pas les bornes de 'coup' (tu le teste dans ta fonction jouerCoup, tu devrais le faire dans testerCoup)
Dans ta fonction 'jouer' tu fais une 2ème boucle si l'utilisateur a entré un coup non valide, tu peux simplifier
Dans ta fonction affichage, tu fais un %3, mais si tu changes la taille de ton tableau, ça ne fonctionnera plus
Tu appelles 2 fois ta fonction testerGagnant par boucle (une fois dans le if et une fois dans le while)
Dans l'ensemble c'est correct. Maintenant, tu pourrais améliorer ton code pour qu'il soit plus évolutif (genre modifier la taille de la grille).
Et éventuellement d'autres choses (genre si je veux modifier les signes des joueurs, je dois le faire dans plusieurs fonctions).
Endorion >
Le prototype de ta fonction 'affiche' est faux, tableau est un tableau et non un pointeur de pointeur.
Le prototype aurait dû être : void affiche (int * tableau,int tailleTableau)
Tu pourrais utiliser un double boucle dans ta fonction affiche
Le prototype de ta fonction testCoup est faux pour les mêmes raisons citées plus haut
Pareil pour coupGagnant et grilleRemplit
Si tu entres 2 fois le même coup, ça t'affiches 'Coup impossible' mais ça change quand même de joueur
Dans ta fonction coupGagant, tu testes la grille, tu devrais tester le joueur courant (ça ne devrait pas arriver normalement, rien de faux dans ton code)
Pour savoir si tu as gagné ou égalité, tu devrais faire ça dans une fonction et non dans plusieurs fonctions différentes
Dans l'ensemble, c'est correct, merci pour ta participation.
Oups en effet j'avais pas vu que j'ai fais la faute un peu partout
J'ai rectifier donc tous les prototypes & fonctions , j'ai aussi changer le bug du "coup impossible", je peux rectifier les autres problèmes aussi mais sa fais trop brouillon et code bidoullié ce qui ne me plait pas trop ...
Il faudrait que je recommence sur un nouveau "plan"
Moi qui avait prévu d'avancer un peu dans le cours je vais me re-pencher sur la question
ÉDIT : voila le résultat après une reprise du sujet , le code marche et sans bug apparent ( enfin peut-être que je ne suis pas allée fouiné assez loin)
les changements sont :
_ rectifications des prototypes ( avec changement des noms pour la plupars des fonctions et variables ( j'ai tout repris de zéro ))
_ Utilisation ( ou du moin tentative ) d'affichage avec la double boucle comme tu m'a dis ( je sais pas si c'est ce que tu avait en tête mais moi j'ai pensé a un truc comme ça )
_ Réparation du bug "Coup impossible"
_ la décision entre égalité et égale est dorénavant dans la même fonction.
En esperant ne pas avoir fais d'autre erreurs ( je pense qu'il y en a que je n'ais pas vu )
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void afficherGrille (int *grille);
int ReceptionCoup (int joueur, int *grille);
int TestCoup (int i, int *grille);
void jouerCoup (int coup, int *grille, int joueur);
void changementJoueur (int *joueur);
void etatGrille (int *gameOver , int *grille, int joueur);
int main()
{
int grilleDeJeu [9] = {'.', '.','.','.','.','.','.','.','.'}, joueur = 0, gameOver = 0, coupJouer = 0;
srand(time(NULL));
joueur = rand() % 2 + 1;
printf("Le joueur 1 a les pions X\nLe joueur 2 a les pions O\n\n");
printf("Joueur %d commence !\n\n", joueur);
afficherGrille(grilleDeJeu);
do
{
coupJouer = ReceptionCoup(joueur, grilleDeJeu);
jouerCoup(coupJouer, grilleDeJeu, joueur);
afficherGrille(grilleDeJeu);
etatGrille(&gameOver, grilleDeJeu, joueur);
changementJoueur(&joueur);
} while ( gameOver != 1);
return 0;
}
void afficherGrille (int *grille)
{
int i = 0,j = 0;
for (i = 0 ; i < 3 ; i++)
{
for (j = (i * 3) ; j < (3 + i * 3 ); j++)
{
printf(" %c ", grille[j]);
}
printf("\n\n");
}
}
int ReceptionCoup (int joueur, int *grille)
{
int reception = 0, bonneEntre = 0;
while (bonneEntre != 1)
{
printf("Joueur %d : ", joueur);
scanf("%d", &reception);
printf("\n");
if (reception > 0 && reception < 10)
{
reception--;
bonneEntre = TestCoup(reception, grille);
}
else
{
printf("Coup impossible \n\n");
}
}
return reception;
}
int TestCoup (int i, int *grille)
{
int test = 0;
if (grille[i] == '.')
{
test = 1;
}
else
{
printf("Coup impossible \n\n");
}
return test;
}
void jouerCoup (int coup, int *grille, int joueur)
{
if (joueur == 1)
{
grille[coup] = 'X';
}
else
{
grille[coup] = 'O';
}
}
void changementJoueur (int *joueur)
{
if (*joueur == 1)
{
*joueur = 2;
}
else
{
*joueur = 1;
}
}
void etatGrille (int *gameOver , int *grille, int joueur)
{
if ((grille[0] == grille[1] && grille[0] == grille[2] && grille[0] != '.')||
(grille[3] == grille[4] && grille[3] == grille[5] && grille[3] != '.') ||
(grille[6] == grille[7] && grille[6] == grille[8] && grille[6] != '.') ||
(grille[0] == grille[3] && grille[0] == grille[6] && grille[0] != '.') ||
(grille[1] == grille[4] && grille[1] == grille[7] && grille[1] != '.') ||
(grille[2] == grille[5] && grille[2] == grille[8] && grille[2] != '.') ||
(grille[0] == grille[4] && grille[0] == grille[8] && grille[0] != '.') ||
(grille[2] == grille[4] && grille[2] == grille[6] && grille[2] != '.'))
{
*gameOver = 1;
printf("Joueur %d gagne !\n\n", joueur);
}
else
{
int i = 0, j = 0;
for (i = 0 ; i < 9 ; i++)
{
if (grille [i] != '.')
{
j++;
}
}
if (j == 9)
{
*gameOver = 1;
printf("Egalite parfaite !!\n\n");
}
}
}
Désolé, t'es passé entre 2, j'ai pas vu.
ggned2 >
Les fonctions qui ne prennent pas d'arguments on mettra 'void'
Pour tirer ton nombre aléatoire, tu peux faire plus simple, inutile de faire plein d'opérations : joueur = rand() % 2 + 1
On évitera d'utiliser des variables globales
Tu pourrais faire une fonction 'rejouer'
On évitera la macro 'ligne' ou alors on ne mettra pas de ';' à la fin et on donnera un nom plus explicite (afficheNouvelleLigne par ex.)
RIEN n'est pas déclaré
Hmm, pour ta fonction 'testerGagnant' j'ai un doute sur ta condition 'test == ROND', tu sors directement de la boucle non ?
Tu ne m'as pas donné main.h
j'adore les variables globales c'est plus facile
sinon il faut mettre plein d'arguments et de machins ! !
j'ai mêmee essayé de faire des SDL_Surface globales
Tu as tort de faire ça. Tu pensera que ça va te faciliter la tâche au début, mais quand tu attaquera des projets un peu plus ambitieux tu vas vite t'y perdre et ton code deviendra incompréhensible... C'est pas une habitude à prendre : utilises les seulement lorsque c'est vraiment nécessaire et qu'il n'y a pas d'autres solutions.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles - ♡ Copying is an act of love.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles - ♡ Copying is an act of love.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles - ♡ Copying is an act of love.