Puissance 4 en C. (Tutoriel de Zds)

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour, suite au tutoriel sur le C, j'ai essayé de faire le puissance 4 mais j'ai un soucis.

Voilà le code des fonctions :

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <stdio.h>
#include <stdlib.h>
#include "puiss4Proto.h"





void Puiss4_alloc(Puiss4 A, int lignes, int colonnes)
{
  int i;
  A->data = malloc(sizeof(char*) * lignes);
  if(A->data == NULL)
  {
    fprintf(stderr, "Puiss4_alloc : Echec de l'allocation\n");
  }
  for(i = 0 ; i < colonnes ; i++)
  {
    A->data[i] = malloc(sizeof(char) * colonnes);
    if(A->data[i] == NULL)
    {
      fprintf(stderr, "Puiss4_alloc : Echech de l'allocation\n");
    }
  }

}
Puiss4 Puiss4_create(int lignes, int colonnes, char caractere)
{
  int j, i;
  Puiss4 A = malloc(sizeof(struct _Puiss4));
  A->lignes = lignes;
  A->colonnes = colonnes;
  A->caractere = caractere;
  Puiss4_alloc(A, lignes, colonnes);
  for(j = 0 ; j < lignes ; j++)
  {
    for(i = 0 ; i < colonnes ; i++)
    {
      A->data[j][i] = caractere;
    }
  }
  return A;
}
void Puiss4_print(Puiss4 A)
{
  int j, i;
  for(j = 0 ; j < A->lignes ; j++)
  {
    printf("\n");
    for(i = 0 ; i < A->colonnes ; i++)
    {
        printf("| ");
        printf("%c", A->data[j][i]);
    }
  }
}
void Puiss4_destroy(Puiss4 A, int lignes, int colonnes)
{
  int j;
  for(j = 0 ; j < lignes ; j++)
  {
    free(A->data[j]);
  }
  free(A);
}
void Puiss4_add(Puiss4 A, int nb_case, char caractere)
{
  int j;
  if((nb_case > A->colonnes) || (nb_case < 0))
  {
    fprintf(stderr, "Puiss4_add : %d out of bounds\n", nb_case);
  }
  int current_indice = Puiss4_indice(A, nb_case);
  printf("1 | current_indice : %d\n", current_indice);
  for(j = 0; j > current_indice ; j--)
  {
    if((A->data[j][nb_case - 1] == 'x') || (A->data[j][nb_case - 1] == 'o'))
    {
      current_indice++;
      printf("2 | current_indice : %d\n", current_indice);
    }
  }
    A->data[current_indice - 1][nb_case - 1] = caractere;

}


int Puiss4_indice(Puiss4 A, int nb_case)
{
  int current_indice = 0;
  int j;
  for(j = 0 ; j < A->lignes ; j++)
  {
      if((A->data[j][nb_case - 1] == 'x') || (A->data[j][nb_case - 1] == 'o'))
      {
        current_indice = j;
        printf("Current_indice : %d\n", current_indice);
        return current_indice;
      }

  }
}
int Puiss4_parcours_vertical(Puiss4 A, int nb_case)
{
  int j;
  int compteur = 1;
  for(j = 0 ; j < A->lignes - 1 ; j++)
  {
    if(A->data[j][nb_case - 1] == A->data[j + 1][nb_case - 1])
    {
      compteur++;
    }
    else
      compteur = 1;

  }
  return compteur;
}

/*void Puiss4_parcours_diagonal(Puiss4 A)
{

}*/
int Puiss4_parcours_horizontal(Puiss4 A, int nb_case)
{
  int i;
  int compteur = 1;
  printf("Compteur : %d\n", compteur);
  int current_indice = Puiss4_indice(A, nb_case);
  for(i = 0 ; i < A->colonnes - 1 ;i++)
  {
    if(A->data[current_indice - 1][i] == A->data[current_indice - 1][i + 1])
    {
      compteur++;
      printf("%c = %c \n", A->data[current_indice - 1][i],A->data[current_indice - 1][i + 1]);
      printf("Compteur : %d\n", compteur);
    }
    else
      compteur = 1;
  }
  return compteur;
}

Le main :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdio.h>
#include <stdlib.h>
#include "puiss4Proto.h"
#define sortie 4


int main(int argc, char** argv)
{
  int indice = 0;
  int nb_case = 0;
  int compteur;
  int compteur2;
  /*int sortie = 4;*/

  Puiss4 A = Puiss4_create(6, 7, ' ');
  printf("Bienvenue sur le jeu du Puissance 4 !\n");
  printf("Joueur 1 : x\n");
  printf("Joueur 2 : o\n");


  while(compteur != sortie)
  {
  Puiss4_print(A);
  printf("\n");
  indice = Puiss4_indice(A, nb_case);
  printf("\n");
  printf("Joueur 1 : ");
  scanf("%d", &nb_case);
  Puiss4_add(A, nb_case, 'x');
  Puiss4_print(A);
  printf("\n");
  compteur = Puiss4_parcours_vertical(A, nb_case);
  printf("Puiss4_parcours_vertical : Compteur | Sortie = %d | %d \n", compteur, sortie);
  printf("\n");
  /*compteur2 = Puiss4_parcours_horizontal(A, nb_case);
  printf("Puiss4_parcours_horizontal : Compteur | Sortie = %d | %d \n", compteur2, sortie);
  printf("\n");*/
  indice = Puiss4_indice(A, nb_case);
  printf("\n");
  printf("Joueur 2 : ");
  scanf("%d", &nb_case);
  Puiss4_add(A, nb_case, 'o');
  printf("\n");
  Puiss4_print(A);
  printf("\n");
  compteur = Puiss4_parcours_vertical(A, nb_case);
  printf("Puiss4_parcours_vertical : Compteur | sortie = %d | %d\n", compteur, sortie);
  printf("\n");
  /*compteur2 = Puiss4_parcours_horizontal(A, nb_case);
  printf("Puiss4_parcours_horizontal : Compteur | Sortie = %d | %d \n", compteur2, sortie);
  printf("\n");*/
  indice = Puiss4_indice(A, nb_case);
  printf("\n");
  }

  Puiss4_destroy(A, 6, 7);
  printf("Vous avez gagné !\n");

  return EXIT_SUCCESS;
}

Donc voilà le problème se situe au niveau de la fonction Puiss4_parcours_horizontal, dès le premier caractère saisi, compteur est égal à 7 alors qu'il devrait être égal à 1, ce que je comprends pas c'est que avec la fonction Puiss4_parcours_vertical ça marche parfaitement.

ce que m'affiche la fonction qui marche :

1
2
3
4
5
6
7
|  |  |  |  |  |  |  
|  |  |  |  |  |  |  
|  |  |  |  |  |  |  
|  |  |  |  |  |  |  
|  |  |  |  |  |  |  
| x|  |  |  |  |  |  
Puiss4_parcours_vertical : Compteur | Sortie = 1 | 4

celle qui ne marche pas :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|  |  |  |  |  |  |  
|  |  |  |  |  |  |  
|  |  |  |  |  |  |  
|  |  |  |  |  |  |  
|  |  |  |  |  |  |  
| x|  |  |  |  |  |  
Compteur : 1
Current_indice : 5
  =   
Compteur : 2
  =   
Compteur : 3
  =   
Compteur : 4
  =   
Compteur : 5
  =   
Compteur : 6
  =   
Compteur : 7
Puiss4_parcours_horizontal : Compteur | Sortie = 7 | 4 

Current_indice : 5

Merci

Édité par Drakop

+0 -0
Auteur du sujet

Voilà :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
#include <stdlib.h>

typedef struct _Puiss4 S_Puiss4;
typedef struct _Puiss4* Puiss4;


struct _Puiss4 {

  char** data;
  int lignes;
  int colonnes;
  char caractere;

};

void Puiss4_alloc(Puiss4 A, int lignes, int colonnes);
Puiss4 Puiss4_create(int lignes, int colonnes, char caractere);
void Puiss4_print(Puiss4 A);
void Puiss4_destroy(Puiss4 A, int lignes, int colonnes);
void Puiss4_add(Puiss4 A, int nb_case, char caractere);
int Puiss4_indice(Puiss4 A, int nb_case);
int Puiss4_parcours_vertical(Puiss4 A, int nb_case);
int Puiss4_parcours_diagonal(Puiss4 A);
int Puiss4_parcours_horizontal(Puiss4 A, int nb_case);
+0 -0

Juste comme ça il manque les directives de préprocesseur pour éviter les inclusions multiples dans Puiss4Proto.h.

Partie du cour de ZdS qui en parle ici

« La Nature est un livre écrit en langage mathématique », Galilée

+0 -0

Salut,

Il manque une partie du code (le header) pour pouvoir tester.

En l'état ton bug peut sans doute être reproduit dans un code plus court (simplifier est une bonne méthode pour le localiser). Tu pourrais aussi préciser plus clairement ce que sont censées faire les fonctions Puiss4_parcours_horizontal/vertical (en particulier, que se passe-t-il s'il y a des espaces, etc.). Plus généralement, c'est bien d'essayer d'utiliser des identificateurs assez descriptifs, mais il faudrait le faire à meilleur escient (en vrac, il me semble : nb_case est un indice de colonne, current_indice l'indice minimal de la colonne sur lequel il y a une pièce, etc.). Bon et puis ça :

1
for(j = 0; j > current_indice ; j--)

me paraît également assez suspect (même si pas forcément lié à ton erreur, que tu devrais aussi plus précisément décrire : qu'est-ce que tu obtiens, qu'est-ce que tu voulais obtenir ? On n'est pas forcément familiers avec tes conventions de nommage/le fonctionnement de ton code, donc ça aide).

Bon courage ! ;)

ÉDIT : à la liste des suspects, rajouter le return de Puiss4_indice qui pourrait lui aussi poser quelques problèmes apcr.

Édité par Lucas-84

Staff

@Drakop : merci. :)
Donc, après lecture, voici ce que je peux dire :

  1. Ligne 21 du fichier main.c, tu utilises la variable compteur alors qu'elle n'a pas été initialisée. Par ailleurs, mais il s'agit là d'une remarque, évite les minuscules pour écrire l'identificateur d'une macro.
  2. Je ne comprends pas bien le rôle de la fonction Puiss4_indice() ou, plus précisément, son utilité pour les autres fonctions.
  3. Dans la fonction Puiss4_add(), la boucle avec pour condition j > current_indice est a priori inutile puisque l'indice vaut toujours au moins zéro, à moins que tu ne voulais incrémenter la variable j et non la décrémenter ?
  4. Tu ne vérifies pas le retour de la fonction scanf() et ne vide pas le tampon d'entrée. Également, tu ne vérifies pas toujours si les données entrées sont valides.

Plus globalement, je pense que tu devrais remettre tes idées à plat et reparcourir ensuite ton code, ce dernier me semblant un peu confus. N'hésite à t'aider des corrections à cet effet, elles sont là pour t'aiguiller. ;)

Édit : semi-grillé par Lucas-84. :-°

Édité par Taurre

+0 -0
Auteur du sujet

Merci pour vos réponses !

  • Pour ce qui est du rôle de la fonction Puiss4_indice permet de calculer le dernier indice la ou il y a une pièce en fonction des colonnes (nb_case).

-J'ai corrigé pour la fonction Puiss_add(), en effet j'avais un pb avec cette fonction et j'ai fait qq modifs et ça a marché. En fait j'ai réussi à faire fonctionner ma fonction en faisant une boucle qui ne marche pas … :honte:

-Je pensais qu'il fallait vider le tampon dans le cadre de caractère comme pour un jeu d'un pendu, je savais pas qu'il fallait le faire ici, tu veux dire quoi par "vérifier le retour de la fonction scanf" ? tu veux dire, vérifier si la donnée entrée est valide ?

Lucas-84 -Pour les fonctions Puiss4_parcours_horizontal/vertical, je les utilise pour parcourir le tableau de façon verticale une fois en fonction de l'indice de colonne(nb_case) et incrémente la variable compteur à chaque fois que les pièces sont identiques et sinon remet la valeur de compteur à 1.Même principe pour l'autre. que veux tu dire par espaces ?

Édité par Drakop

+0 -0
Staff

-Je pensais qu'il fallait vider le tampon dans le cadre de caractère comme pour un jeu d'un pendu, je savais pas qu'il fallait le faire ici, tu veux dire quoi par "vérifier le retour de la fonction scanf" ? tu veux dire, vérifier si la donnée entrée est valide ?

Drakop

Effectivement, cette histoire de tampon n'est présentée que dans le chapitre sur les chaînes (ce qui serait peut-être à revoir, finalement…), mais cela vaut pour tout utilisation de scanf(). En fait, il y a un cas où tu peux t'en passer : si tu n'appel scanf() qu'une seule fois, là on s'en fout.

Sinon, pour le retour de la fonction scanf(), je parle de la valeur qu'elle renvoie à savoir le nombre de conversions réussies (si cela ne te dit rien, il en est question au début de ce chapitre).

Édité par Taurre

+0 -0
Auteur du sujet

D'accord merci, je viens de détecter un autre pb :

La fonction qui parcours le tableau de façon verticale marche par contre lorsque j'ai 4 jetons empilé o ça quitte bien la boucle mais lorsque c'est 4 jetons x ça ne quitte pas la boucle alors que compteur est bien égal à 4 et la variable sortie l'est également, la je pige pas trop o_O

+0 -0

Dans un programme, il FAUT des commentaires. Dans ton dernier message, tu dis qu'il y aurait un bug sur la fonction Puiss4_parcours_vertical().

Je regarde donc cette fonction, je vois que dans les paramètres, il y a une variable nb_cases. J'imagine que nb, c'est l'abréviation de nombre, et nb_cases, c'est le nombre de cases de la grille (42 par exemple sur une grille 6x7= .. et donc toujours le même nombre (dépendrait donc juste de la taille de la grille).

Ca ne me semble pas très cohérent, et en recherchant ici ou là, je devine que nb_cases, c'est un numéro de colonne. Tu nous as tendu un piège, j'ai failli tomber dedans.

Et donc, si je comprends bien, dans cette fonction Puiss4_parcours_vertical(), tu parcours toutes les lignes (toujours le même nombre de lignes, que l'on soit au 1er mouvement ou au 30ème…) , et tu comptes combien de pièces identiques consécutives on a.

Si on a 5 cases vides consécutives, sur les 5 lignes du haut, c'est considéré comme 5 symboles identiques ?

Je vois aussi une autre fonction puiss4_indice() … j'imagine que cette fonction sert à quelque chose, et même que cette fonction est essentielle dans le programme. Mais je suis incapable de dire à quoi elle sert.

Juste pour le fun, je te donne rendez-vous dans 3 mois. Dans 3 mois, tu auras oublié le rôle de chaque variable, tu seras dans la même situation que nous. Dans 3 mois, relis la question que tu as posée aujourd'hui, et tu verras que ton code est incompréhensible.

Quand on écrit une fonction, comme par exemple ta fonction Puiss4_parcours_vertical(), dans un premier temps, on écrit 3 ou 4 lignes de commentaires, avec la signification de chaque paramètre, et le rôle de la fonction, puis ensuite on commence à coder. Si on commence à coder avant d'écrire les commentaires, c'est mort.

Édité par elegance

+1 -0
Auteur du sujet

Re-bonjour j'ai réessayé de refaire la fonction Puiss4_parcours_vertical car elle était bugée, en parcourant le tableau colonne par colonne même celles ou ce n'était pas nécessaire :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int Puiss4_parcours_vertical(Puiss4 A, int nb_case)
{
int j,i;
int compteur = 1;
for(i = 0 ; i < A->colonnes - 1 ; i++)
{
  for(j = 0 ; j < A->lignes - 1 ; j++)
  {
    if(A->data[j][i] == 'x')
    {
      if(A->data[j][i] == A->data[j + 1][i])
      {
        compteur++;
      }
      else if(A->data[j][i] != A->data[j + 1][i])
      {
            compteur = 1;
      }
    }
  }
}

  return compteur;
}

Mais j'ai exactement les même problèmes qu'avant :

-Lorsque j'ai 4 pions x allignés la boucle ne s'arrête pas, mais s'arrête à 4 o.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
|  |  |  |  |  |  |  
|  |  |  |  |  |  |  
| x| o|  |  |  |  |  
| x| o|  |  |  |  |  
| x| o|  |  |  |  |  
| x| o|  |  |  |  |  
Puiss4_parcours_vertical : Compteur | sortie = 4 | 4

Current_indice : 2

Vous avez gagné !

-Ensuite j'ai un autre bug assez bizarre :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
|  |  |  |  |  |  |  
|  |  |  |  |  |  |  
| x|  |  |  |  |  |  
| x| o|  |  |  |  |  
| x| o|  |  |  |  |  
| x| o| o|  |  |  |  
Puiss4_parcours_vertical : Compteur | sortie = 4 | 4

Current_indice : 5

Vous avez gagné !

if(A->data[j][i] == 'x') -> j'ai écrit cette ligne car le compteur eétait trop élevé, donc ct bien ça le pb avec la fonction horizontal mais je comprends pas pourquoi ça le faisait pas avec l'ancienne fonction parcours_vertical.

Je n'ai plus trop d'idée la :'( donc si des gens pourraient me donner des conseils pour implémenter les fonctions de parcours de tableau 2D horizontal/vertical avec la gestion des caractères x/o ça serait cool ! parce que le pb c'est que le champ vide est compté comme qq chose dans le tableau du coup le compteur est trop élevé :/

Édité par Drakop

+0 -0
Auteur du sujet

Je viens d'éditer mon message, en fait je voudrais parcourir le tableau 2d verticalement de l'indice 0 à n - 1, et incrémenter le compteur à chaque fois que le deux pions sont les même donc le compteur est initialisé à 1 puis incrémenter jusqu'à 4 , mais je n'arrive pas à gérer les différents pions et les espaces vides, je vois pas comment faire, je suis un peu perdu.

Et ensuite j'aimerais faire la même chose horizontalement et en diagonale

Édité par Drakop

+0 -0

Toujours pas la moindre ligne de commentaire, mais passons.

Quand un joueur joue un coup, il remplit une certaine case Cij. Si tu veux optimiser ton programme, ou si plus modestement, tu veux qu'il marche, il y a seulement 4 lignes à tester : - la verticale partant de Cij vers le bas. - L'horizontale passant par Cij, mais qui peut partir vers la droite ou vers la gauche ou de part et d'autre de Cij. - Et les 2 diagonales montante et descendante autour de Cij.

Donc dans tes fonctions parcours_Vertical() etc, ça me paraît essentiel de passer i et j en paramètres.

Dans ta dernière version de parcours_vertical(), tu fais un calcul sur la colonne 1, puis un calcul sur la colonne 2, qui efface ce que tu viens de calculer pour la colonne 1 , etc etc..

+0 -0
Auteur du sujet

Bonjour j'ai essayé de faire la fonction parcours_vertical mais ça ne marche toujours pas :

les deux gros pb :

-Avec la nouvelle fonction, problème de compteur, il commence à 5, il compare les espaces vides -> comment puis-je gérer ça ?

-L'ancienne fonction, le prg ne quitte pas la boucle lorsqu'il y a 4 pions 'x' allignés mais la quitte avec 4 pions 'o'.

La nouvelle fonction :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
/*Fonction avec en paramètres :
*- nb_case qui correspond à la colonne ou le joueur souhaite mettre son pion;
*- current_indice qui correspond au dernier indice ou se trouve un pion sur cette "nb_case";
* -La foncion part du bas jusqu'à l'indice 0;
*-Si deux pions sont identiques ([j] et [j - 1]) alors on incrémente compteur puis on décrémente j.
*-Sinon on remet compteur à 1.
*/
int Puiss4_parcours_vertical(Puiss4 A, int nb_case, int current_indice)
{
  int compteur= 1;
  int j,i;
  for(j = current_indice - 1 ; j != 0 ; j--)
  {
    if(A->data[j][nb_case - 1] == A->data[j - 1][nb_case - 1])
      compteur++;
    else
      compteur = 1;
    }
    return compteur;
}

Pensez-vous que la fonction est bonne ou je dois revoir la méthode ? Peut-être que je dois regarder du coté du main, mais je vois pas la.

+0 -0

Dans ta boucle, tu pars du point où tu as posé un pion. ( colonne nb_case, ligne current_indice). Tu parcours les points à la verticale de ce point, tant que le symbole est le même. MAIS, dès que tu trouves un symbole différent, il faut faire en sorte de SORTIR de ta boucle ou de ta procédure.

+0 -0
Auteur du sujet

Merci de ta réponse tu parles de sortir de la boucle,mais dès que tu as un symbole différent il ne faut pas forcément sortir de la boucle non ?

1
2
3
4
5
6
| x|  |  |  |  |  |  
| x|  |  |  |  |  |  
| x|  |  |  |  |  |  
| x|  |  |  |  |  |  
| o|  |  |  |  |  |  
| x|  |  |  |  |  |  

La tu as deux pions différents au début mais c'est toujours possible d'avoir les 4 pions alignés, ou alors j'ai pas bien compris ce que tu as voulu dire

Édité par Drakop

+0 -0

Dans les commentaires de ta fonction, tu as écrit : ' La foncion part du bas jusqu'à l'indice 0; '

Cette phrase ne veut rien dire… Essaie déjà d'écrire commence la fonction va fonctionner, en FRANçAIS clair, ensuite, tu traduiras en C ou en Espagnol… Mais là, tu essaies d'écrire dans une langue étrangère, sans avoir d'abord formulé CLAIREMENT en français ce que tu cherchais à faire.

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte