Forum Programmation.c Puissance 4, problème avec l'affichage du gagnant

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
0
4
déc.
2021

Bonjour,

Je suis en train d créer un puissance 4 en C mais le problème est que quand il y a 4 pions alignés le programme ne s'arrête pas en affichant le gagnant, le programme continue jusqu'à ce que la grille soit remplie.
Mais je ne vois pas le problème dans ma fonction aGagne.. Auriez vous des solutions à me proposer ?

Merci d'avance !

Mon code :

void init (int ttint_plateau[N][N]){
    int int_i;
    int int_j;
    for(int_i=0;int_i<N;int_i++){
        for(int_j=0;int_j<N;int_j++){
            ttint_plateau[int_i][int_j]=' ';
        }
    }
}

void affichage(int ttint_plateau[N][N]){
    int int_i;
    int int_j;
    printf("   0   1   2   3   4  \n");
    for(int_i=0;int_i<N;int_i++){
        printf(" +---+---+---+---+---+\n");
        printf("%d|",int_i);
        for(int_j=0;int_j<N;int_j++){
            ttint_plateau[int_i][int_j];
            printf("%c  |", ttint_plateau[int_i][int_j]);
        }
        printf("\n");
    }
    printf(" +---+---+---+---+---+\n");
}

int jouer (int ttint_plateau[N][N], int int_joueur, int int_x){
    int retour_choixCol;
    int int_choixCol;
    int int_ligne;
    int_ligne=5;
    do {
        printf("Joueur %d, entrez un numéro de colonne entre 0 et 4 :\n", int_joueur);
        retour_choixCol=scanf("%d", &int_choixCol);
        if(retour_choixCol==1){
            while(ttint_plateau[int_ligne][int_choixCol]!=' '){
                if(int_ligne>=1){
                    int_ligne=int_ligne-1;
                }else{
                    printf("Cette colonne est remplie perdu !!");
                    exit(ERREURSAISIE);
                }
            }
            if(int_x==1){
                ttint_plateau[int_ligne][int_choixCol]='O';
                return(ttint_plateau);
            }else{
                ttint_plateau[int_ligne][int_choixCol]='X';
                return(ttint_plateau); 
            }
        }else{
            return(ERREURSAISIE);
        }
    }while(int_choixCol<0 || int_choixCol>4);
}

int horizontale(int ttint_plateau[N][N]){
    int int_i;
    int int_j;
    for(int_i=0;int_i<N;int_i++){
        for(int_j=0;int_j<2;int_j++){
            if (ttint_plateau[int_i][int_j]==ttint_plateau[int_i][int_j+1]==ttint_plateau[int_i][int_j+2]==ttint_plateau[int_i][int_j+3]&& ttint_plateau[int_i][int_j]!=' '){
                if(ttint_plateau[int_i][int_j]=='0'){
                    return(1);
                }else{
                    return(2);
                }
            }
        }
    }
    return(-1);
}

int verticale(int ttint_plateau[N][N]){
    int int_i;
    int int_j;
    for(int_j=0;int_j<N;int_j++){
        for(int_i=0;int_i<2;int_i++){
            if (ttint_plateau[int_i][int_j]==ttint_plateau[int_i+1][int_j]==ttint_plateau[int_i+2][int_j]==ttint_plateau[int_i+3][int_j] && ttint_plateau[int_i][int_j]!=' '){
                if(ttint_plateau[int_i][int_j]=='0'){
                    return(1);
                }else{
                    return(2);
                }
            }
        }
    }
    return(-1);
}

int diagonaledroite(int ttint_plateau[N][N]){
    int int_i;
    int int_j;
    for(int_i=0;int_i<2;int_i++){
        for(int_j=0;int_j<2;int_j++){
            if (ttint_plateau[int_i+3][int_j]==ttint_plateau[int_i+2][int_j+1]==ttint_plateau[int_i+1][int_j+2]==ttint_plateau[int_i][int_j+3] && ttint_plateau[int_i+3][int_j]!=' '){
                if(ttint_plateau[int_i+3][int_j]=='0'){
                    return(1);
                }else{
                    return(2);
                }
            }
        }
    }
    return(-1);
}

int diagonalegauche(int ttint_plateau[N][N]){
    int int_i;
    int int_j;
    for(int_j=0;int_j<2;int_j++){
        for(int_i=1;int_i>=0;int_i--){
           if (ttint_plateau[int_i][int_j]==ttint_plateau[int_i+1][int_j+1]==ttint_plateau[int_i+2][int_j+2]==ttint_plateau[int_i+3][int_j+3] && ttint_plateau[int_i][int_j]!=' '){
               if(ttint_plateau[int_i][int_j]=='0'){
                    return(1);
                }else{
                    return(2);
                }
           }
        }
    }
    return(-1);
}

int caserestante(int ttint_plateau[N][N]){
    int int_i;
    int int_j;
    for(int_i=0;int_i<N;int_i++){
        for(int_j=0;int_j<2;int_j++){
            if(ttint_plateau[0][0]!=' '&&ttint_plateau[0][1]!=' '&&ttint_plateau[0][2]!=' '&&ttint_plateau[0][3]!=' '&&ttint_plateau[0][4]!=' '){
                return(0);
            }
        }
    }
    return(-1);
}


int aGagne(int ttint_plateau[N][N]){
    if(verticale(ttint_plateau)==1 || verticale(ttint_plateau)==2){
        return(verticale(ttint_plateau));
        printf("Le joueur %d a gagné !", verticale(ttint_plateau));
    }else{
        if(horizontale(ttint_plateau)==1 || horizontale(ttint_plateau)==2){
            return(horizontale(ttint_plateau));
            printf("Le joueur %d a gagné !", horizontale(ttint_plateau));
        }else{
            if(diagonaledroite(ttint_plateau)==1 || diagonaledroite(ttint_plateau)==2){
                return(diagonaledroite(ttint_plateau));
                printf("Le joueur %d a gagné !", diagonaledroite(ttint_plateau));
            }else{
                if(diagonalegauche(ttint_plateau)==1 || diagonalegauche(ttint_plateau)==2){
                    return(diagonalegauche(ttint_plateau));
                    printf("Le joueur %d a gagné !", diagonalegauche(ttint_plateau));
                }else{
                    if(caserestante(ttint_plateau)==0){
                        return(0);
                        printf("match nul...");
                    }else{
                        return(-1);
                    }
                }
            }
        }
    }   
}

void tourDeJeu(int ttint_plateau[N][N]){
    int int_i;
    int int_j;
    int int_joueur;
    while(aGagne(ttint_plateau)==-1){
        for(int_joueur=1;int_joueur<=2;int_joueur++){
            jouer(ttint_plateau, int_joueur, int_joueur);
            affichage(ttint_plateau);
            aGagne(ttint_plateau);
            printf("%d\n", aGagne(ttint_plateau));
            if(aGagne(ttint_plateau)==0 || aGagne(ttint_plateau)==1 || aGagne(ttint_plateau)==2){
                printf("%d",aGagne(ttint_plateau));
                            exit(-1);
            }
        }
    }
}
  • # Dur à comprendre

    Posté par  (Mastodon) . Évalué à 6.

    C'est pas facile de t'aider, parce qu'il faut entrer dans ton code, et tel qu'il est écrit c'est compliqué (et j'avoue que même si j'aime les os à ronger, je vais pas faire trop d'effort).

    1/ Il n'y a aucun commentaire

    La fonction ttint() par exemple, elle fait quoi ? Pourquoi ? Quelles valeurs elle retourne ? Rien n'est évident, même verticale() on sait pas ce qu'elle fait.

    2/ Les valeurs de retour sont incompréhensible

    Ça retourne 2 ou 1 ou -1… pourquoi pas, mais à ce moment il te faut faire un #define style :

    #define RET_TROUVE_COLONNE 1

    et après un code comme if (cherche_colonne() == RET_TROUVE_CONONNE) c'est bcp plus facile à comprendre

    une fonction comme aGagne par exemple on s'attend à ce qu'elle retour true ou false, son prototype serait donc

    bool aGagne(...) {
      if ... {
        return true;
      } else {
        return false;
      }
    }

    3/ Trop de else if imbriqués

    Tu dois avoir manqué quelqchose sur tes algo de base, parce que envoyer une grande suite de if imbriqés avec seuelment un indice de tableau qui change… ça sent vraiment qu'il y a mieux à écrire :)

    En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

    • [^] # Re: Dur à comprendre

      Posté par  . Évalué à 1.

      Oui désolé pour le manque de commentaire, en général je le fais quand j'ai terminé mais sur des programmes de cette taille c'est vrai que ce n'est pas une bonne idée de procéder comme ça..

      • [^] # Re: Dur à comprendre

        Posté par  (site web personnel) . Évalué à 7.

        Honnêtement, à la place de mettre des commentaires, met du code qui se comprend sans ambiguïté et met des tests. :)

        Adhérer à l'April, ça vous tente ?

    • [^] # Re: Dur à comprendre

      Posté par  (site web personnel) . Évalué à 2.

      bool aGagne(...) {
        if ... {
          return true;
        } else {
          return false;
        }
      }

      Plutôt :

      bool aGagne(...) {
          return ...;
      }

      git is great because linus did it, mercurial is better because he didn't

  • # commentaires

    Posté par  (site web personnel) . Évalué à 4.

    Ce n'est pas forcément dans aGagne() que se trouve le problème. Est-ce que ça ne marche pas dans tous les cas où il y a 4 pions alignés ? (verticale, horizontale, diagonales droite et gauche)

    Dans ce bloc, il y a des choses étranges :

                aGagne(ttint_plateau);
                printf("%d\n", aGagne(ttint_plateau));
                if(aGagne(ttint_plateau)==0 || aGagne(ttint_plateau)==1 || aGagne(ttint_plateau)==2){
                    printf("%d",aGagne(ttint_plateau));

    A quoi sert le premier appel aGagne(ttint_plateau) ? L'entier retourné n'est pas récupéré dans une variable, qui permettrait en plus de ne pas appeler à nouveau cinq fois la fonction ! Même remarque dans aGagne().

    Dans aGagne(), les return devraient être après les printf, sinon ils ne sont pas exécutés car on a déjà quitté la fonction.

    Le problème doit venir des tests d'égalité de quatre cases : en C, on ne peut tester l'égalité que de deux variables à la fois, on ne peut pas les enchaîner comme ça :

    if (ttint_plateau[int_i][int_j]==ttint_plateau[int_i][int_j+1]==ttint_plateau[int_i][int_j+2]==ttint_plateau[int_i][int_j+3]&& ttint_plateau[int_i][int_j]!=' '){

    Donc il manque des &&.

    • [^] # Re: commentaires

      Posté par  . Évalué à 2.

      Merci beaucoup pour votre aide vous avez vu juste, je le saurais pour la prochaine fois ! :)

  • # vieux souvenirs de code

    Posté par  . Évalué à 6.

    il me semble qu'un "return" dans un IF va quitter la section

    du coup

    if(verticale(ttint_plateau)==1 || verticale(ttint_plateau)==2){
            return(verticale(ttint_plateau));
            printf("Le joueur %d a gagné !", verticale(ttint_plateau));
        }
    //[...]

    va sortir de la section AVANT d'afficher 'le joueur XXX a gagné !'
    et donner a la suite, la valeur du ttint_plateau

    • [^] # Re: vieux souvenirs de code

      Posté par  . Évalué à 1. Dernière modification le 05 décembre 2021 à 18:01.

      Oui vous avez raison, merci !

    • [^] # Re: vieux souvenirs de code

      Posté par  . Évalué à 5. Dernière modification le 06 décembre 2021 à 10:30.

      autre remarque, si verticale(param) ne modifie pas ce dernier, ne l'appelle pas 4 fois de suite c'est très mauvais coté perf
      utilise une variable locale

      et comme dit plus haut, met des noms qui veulent dire quelque chose.

      int res_verticale = verticale(ttint_plateau);

      ah et d'un point de vue style

      if (...) {
      } 
      else {
        if (...) {
        } else {
          if(...) {
          }
          else {
           if (...) 
         } 
        }
       }
      
      }

      c'est non

      if (...){
      } else if (...) {
      } else if (...) {
      } else if (...) {
      } else {
      }

      est beaucoup plus lisible!!!

      Il ne faut pas décorner les boeufs avant d'avoir semé le vent

      • [^] # Re: vieux souvenirs de code

        Posté par  . Évalué à 6.

        Bon et après le style, c'est les perfs.

        C'est tout simplement catastrophique!

        pour chaque tour de jeu tu teste l'intégralité des positions sur tout le plateau… J'ajouterai que si tu changes de dimensions tu va au devant de gros ennuis, au vu des fonctionnement des verticale/horizontales; tu ferais mieux de faire une fonction

        int getGrid(int grid[N][N], int posX, int posY) {
         renvoie la valeur de la case dans la grille ou -1 (ou 0) si en dehors de la grille (en gros <0 ou >=N)
        }
        
        bool hasNumberAligned(int posX, int posY, int grid[N][N], int offsetX, int offset Y) {
           // ici faut s'assurer que les n(4) cases  sont alignés
           int nbOK=1;
           for(int n=1;getGrid(grid, posX - offsetX*n, posY - offsetY*n) == grid[posX][posY] && n < 4; ++n){
             ++nbOK;
           }
           for(int n=1;getGrid(grid, posX + offsetX*n, posY + offsetY*n) == grid[posX][posY] && n < 4; ++n){
             ++nbOK;
           }
           return nbOK >= 4;
        }
        
        bool aGagne(int posX, int posY, int grid[N][N]) {
           // ici on teste les 4 directions possible ça renvoie vrai si ça a gagné
           return hasNumberAligned(posX, posY, grid, 0, 1) || hasNumberAligned(posX, posY, grid, 1, 0) || hasNumberAligned(posX, posY, grid, 1, 1) || hasNumberAligned(posX, posY, grid, 1, -1);
        }

        Il ne faut pas décorner les boeufs avant d'avoir semé le vent

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.