[C] Besoin d'aide pour le Jeux de la Vie

Besoin d'aide pour le Jeux de la Vie [C] - C - Programmation

Marsh Posté le 16-10-2013 à 15:18:35    

Bonjour, nous avons un programme à coder en C, j'utilise codeblocks. Nous devons coder le "jeux de la vie" dont voici les règles :  
 
----------------------------------------------------------------------------------------
Le jeu de la vie évolue normalement sur un damier infini. Chaque case est occupée par une cellule qui peut être vivante ou morte.
A chaque génération, chaque cellule peut naître, mourir, ou rester dans son état. Les règles qui permettent de passer d'une
génération à l'autre sont précises et ont été choisies avec soin pour que l'évolution des organismes soit intéressante et imprévisible.
En premier lieu, notons que sur un damier infini, chaque case a exactement 8 voisins. Pour créer la génération suivante à partir
de la génération courante, J. Conway a fixé les règles suivantes :
 
    Une cellule ayant exactement 2 ou 3 voisins vivants survit la génération suivante.
    Une cellule ayant au moins 4 cellules voisines vivantes meurt d'étouffement à la génération suivante.
    Une cellule ayant au plus une cellule voisine vivante meurt d'isolement à la génération suivante.
    Sur une case vide ayant exactement 3 voisins vivants, une cellule naîtra à la génération suivante.
 
Afin d'implémenter ce jeu, on considère le damier infini comme une matrice "torique". Le damier sera représenté par une matrice
dont les bords droite et gauche sont reliés entre eux, ainsi que les bords supérieur et inférieur.  
----------------------------------------------------------------------------------------
 
J'ai bien avancé sur le code, mais j'ai un petit soucis, la génération suivante de ma matrice, ici j'ai pris une matrice 10*10 est complètement fausse. En effet, toutes les cellules sont vivantes dans ma deuxième matrice excepté la dernière cellule. Je ne trouve pas l'erreur. Je pense qu'elle vient de la fonction "next_gen" ou "nb_voisin". Pour faire une matrice torique (calcul du nb de voisins à la premiere ligne/colonne ou derniere, puisque pour la premiere ligne, il faut regarder les voisins de la derniere ligne par exemple, j'ai utilisé un modulo, je ne sais pas si cela fonctionne correctement)
 
Merci d'avance à ceux qui pourront m'aider et qui auront pris le temps de me lire.
 
Voici mon code:

Code :
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <time.h>
  4. #define TAILLE 10
  5. void init_damier(char damier[TAILLE][TAILLE]); //initialisation du damier
  6. void afficher_matrice(char damier[TAILLE][TAILLE]); //affichage du damier
  7. int nb_voisin(int i, int j, char damier[TAILLE][TAILLE]); //comptage du nombre de voisins vivants/morts
  8. void cel_vivante(char* cellule, int nb_voisin);  //changement des cellules en fonction du nb voisins
  9. void next_gen(char damier[TAILLE][TAILLE]); //generation suivante
  10. void main()
  11. {
  12.   int i,j;
  13.   char damier[TAILLE][TAILLE];
  14.   init_damier(damier);
  15.   afficher_matrice(damier);
  16.   next_gen(damier);
  17.   afficher_matrice(damier);
  18. }
  19. void init_damier(char damier[TAILLE][TAILLE])
  20. {
  21.   int i, j;
  22.   srand(time(NULL)); //cellule aléatoire morte ou vivante
  23.   for (i=0;i<TAILLE;i++)
  24.   {
  25.     for(j=0;j<TAILLE;j++)
  26.       if(rand()%100<20) {damier[i][j]='0';} //un maximum de 20% de cellule vivante
  27.       else {damier[i][j]='-';}
  28.   }
  29. }
  30. void afficher_matrice(char damier[TAILLE][TAILLE])
  31. {
  32.    int i,j;
  33.   for (i=0;i<TAILLE;i++)
  34.   {
  35.     for(j=0;j<TAILLE;j++)
  36.     {
  37.       printf("%c",damier[i][j]);
  38.     }
  39.     printf("\n" );
  40.   }
  41.   printf("\n\n\n" );
  42. }
  43. int nb_voisin(int i, int j, char damier[TAILLE][TAILLE])
  44. {
  45.   int voisin=0;
  46.   if(damier[(i+TAILLE-1)%TAILLE][(j+TAILLE-1)%TAILLE]='0') voisin++; //Utilisation du modulo pour faire une matrice torique (comptage des voisins à la premiere ligne/colonne et derniere ligne/colonne)
  47.   if(damier[(i+TAILLE-1)%TAILLE][j]='0') voisin ++;
  48.   if(damier[(i+TAILLE-1)%TAILLE][(j+TAILLE+1)%TAILLE]='0') voisin++;
  49.   if(damier[i][(j+TAILLE-1)%TAILLE]='0') voisin++;
  50.   if(damier[i][(j+TAILLE+1)%TAILLE]='0') voisin++;
  51.   if(damier[(i+TAILLE+1)%TAILLE][(j+TAILLE-1)%TAILLE]='0') voisin++;
  52.   if(damier[(i+TAILLE+1)%TAILLE][j]='0') voisin++;
  53.   if(damier[(i+TAILLE+1)%TAILLE][(j+TAILLE+1)%TAILLE]='0') voisin++;
  54.   return voisin;
  55. }
  56. void cel_vivante(char* cellule, int nb_voisin)
  57. {
  58.   if (*cellule=='0') //Si la cellule est vivante
  59.   {
  60.    if (nb_voisin>=4) *cellule='-';
  61.    if (nb_voisin<=1) *cellule='-';
  62.   }
  63.   else if (*cellule=='-'); //Si la cellule est morte
  64.   {
  65.    if (nb_voisin==3) *cellule='0';
  66.   }
  67. }
  68. void next_gen(char damier[TAILLE][TAILLE])
  69. {
  70.   int i,j;
  71.   for(i=0;i<TAILLE;i++)
  72.   {
  73.     for(j=0;j<TAILLE;j++)
  74.     {
  75.       cel_vivante(&damier[i][j], nb_voisin(i,j,damier)); //on change la cellule si elle satisfait les conditions
  76.     }
  77.   }
  78. }


Message édité par gilou le 16-10-2013 à 18:51:25
Reply

Marsh Posté le 16-10-2013 à 15:18:35   

Reply

Marsh Posté le 16-10-2013 à 16:58:42    

Tu devrais compiler ton programme avec tous les avertissements activés (-Wall, dans C::B, ça se configure dans Projects => Build options => Compiler settings => Compiler flags). Avec ton code, ça donne :

Code :
  1. main.c:13: warning: return type of 'main' is not `int'
  2. main.c: In function `main':
  3. main.c:14: warning: unused variable `i'
  4. main.c:14: warning: unused variable `j'
  5. main.c: In function `nb_voisin':
  6. main.c:54: warning: suggest parentheses around assignment used as truth value
  7. main.c:55: warning: suggest parentheses around assignment used as truth value
  8. main.c:56: warning: suggest parentheses around assignment used as truth value
  9. main.c:57: warning: suggest parentheses around assignment used as truth value
  10. main.c:58: warning: suggest parentheses around assignment used as truth value
  11. main.c:59: warning: suggest parentheses around assignment used as truth value
  12. main.c:60: warning: suggest parentheses around assignment used as truth value
  13. main.c:61: warning: suggest parentheses around assignment used as truth value


 
Particulièrement les "suggest parentheses around assignment used as truth value". Erreur classique.

Reply

Marsh Posté le 16-10-2013 à 19:15:59    

Enfin la, l'erreur est clairement entre = et ==
 
D'autre part
char damier[TAILLE][TAILLE];
if(rand()%100<20) {damier[i][j]='0';} //un maximum de 20% de cellule vivante
      else {damier[i][j]='-';}
C'est pas une très bonne idée
 
int damier[TAILLE][TAILLE];
if(rand()%100<20) {damier[i][j]= 1;} //un maximum de 20% de cellule vivante
      else {damier[i][j]= 0;}
C'est mieux pour les tests, les évaluations...
Il y a qu'au moment de l'affichage qu'on a besoin de faire
if (damier[i][j])  
    printf("0" );
else
    printf("-" );
 
A+,


Message édité par gilou le 16-10-2013 à 19:16:51

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 16-10-2013 à 22:32:48    

Merci tpierron, j'ai corrigé et ça à l'air de marcher. Par contre je n'arrive pas à activer tous les avertissements dans project, la case build options est grisée.  
 
Merci pour le conseil gilou

Reply

Marsh Posté le 16-10-2013 à 22:37:29    

Alors après réflexion, ça marche bien sur les lignes et les colonnes qui ne sont pas à l'extremité de la matrice, je dois avoir un problème sur les bords avec mon modulo, quelqu'un aurait une idée ?

Reply

Marsh Posté le 16-10-2013 à 23:47:57    

Attention à la différence entre = (un seul signe égal) qui est une affectation, une association, un chargement, et == (deux signes égal) qui est un test d'égalité.  
Dans les if, il faut toujours mettre des ==, sauf dans des cas très particuliers et très rares.

Reply

Marsh Posté le 17-10-2013 à 01:18:22    

yep merci olivthill, j'avais corrigé cette erreur suite aux erreurs que m'a montré tpierron!

Reply

Marsh Posté le 17-10-2013 à 03:02:04    

Ton pb vient probablement de cette ligne ci:
else if (*cellule=='-'); //Si la cellule est morte
 
En utilisant des tableaux d'entier, on peut nettement simplifier la procédure nb_voisin:
 

Code :
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <time.h>
  4. #define TAILLE 10
  5. void init_damier(int (*damier)[TAILLE][TAILLE]); //initialisation du damier
  6. void afficher_matrice(int (*damier)[TAILLE][TAILLE]); //affichage du damier
  7. int nb_voisin(int i, int j, int (*damier)[TAILLE][TAILLE]); //comptage du nombre de voisins vivants/morts
  8. void cel_vivante(int* cellule, int nb_voisin);  //changement des cellules en fonction du nb voisins
  9. void next_gen(int (*damier)[TAILLE][TAILLE]); //generation suivante
  10. #define VIVANTE 1
  11. #define MORTE 0
  12. int main()
  13. {
  14.     int damier[TAILLE][TAILLE];
  15.     srand(time(NULL));
  16.     init_damier(&damier);
  17.     afficher_matrice(&damier);
  18.     next_gen(&damier);
  19.     afficher_matrice(&damier);
  20.     return 0;
  21. }
  22. void init_damier(int (*damier)[TAILLE][TAILLE])
  23. {
  24.     int i, j;
  25.     for (i = 0; i < TAILLE; ++i) {
  26.         for (j = 0; j < TAILLE; ++j) {
  27.             if((rand()%100) < 20) {
  28.                 (*damier)[i][j] = VIVANTE;
  29.             } else  {
  30.                 (*damier)[i][j] = MORTE;
  31.             }
  32.         }
  33.     }
  34. }
  35. void afficher_matrice(int (*damier)[TAILLE][TAILLE])
  36. {
  37.     int i, j;
  38.     for (i = 0; i < TAILLE; ++i) {
  39.         for (j = 0; j < TAILLE; ++j) {
  40.             if ((*damier)[i][j] == VIVANTE) {
  41.                 printf("0" );
  42.             } else {
  43.                 printf("-" );
  44.             }
  45.         }
  46.         printf("\n" );
  47.     }
  48.     printf("\n" );
  49. }
  50. #define MODT(i)  ((TAILLE + (i)) % TAILLE)
  51. int nb_voisin(int i, int j, int (*damier)[TAILLE][TAILLE])
  52. {
  53.     return (*damier)[MODT(i-1)][MODT(j-1)] + (*damier)[MODT(i-1)][MODT(j)]
  54.            + (*damier)[MODT(i-1)][MODT(j+1)] + (*damier)[MODT(i)][MODT(j-1)]
  55.            + (*damier)[MODT(i)][MODT(j+1)] + (*damier)[MODT(i+1)][MODT(j-1)]
  56.            + (*damier)[MODT(i+1)][MODT(j)] + (*damier)[MODT(i+1)][MODT(j+1)];
  57. }
  58. void cel_vivante(int* cellule, int nb_voisin)
  59. {
  60.     if (*cellule == VIVANTE) {
  61.         if ((nb_voisin <= 1) || (nb_voisin >=4)) {
  62.             *cellule = MORTE;
  63.         }
  64.     } else {
  65.         if (nb_voisin == 3) {
  66.             *cellule = VIVANTE;
  67.         }
  68.     }
  69. }
  70. void next_gen(int (*damier)[TAILLE][TAILLE])
  71. {
  72.     int i,j;
  73.     for(i = 0; i < TAILLE; ++i) {
  74.         for (j = 0; j < TAILLE; ++j) {
  75.             cel_vivante(&(*damier)[i][j], nb_voisin(i,j,damier)); //on change la cellule si elle satisfait les conditions
  76.         }
  77.     }
  78. }


Note en faisant
void init_damier(int (*damier)[TAILLE][TAILLE]);
je passe le tableau damier par pointeur ce qui est bien plus léger que passer le tableau tout entier comme tu le fais.
Dans un deuxième temps, plutôt que de se coltiner un int (*damier)[TAILLE][TAILLE] partout, on peut définir un type ad-hoc avec un typedef.
 
A+,


Message édité par gilou le 17-10-2013 à 03:11:37

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 17-10-2013 à 03:18:34    

akl52 a écrit :

yep merci olivthill, j'avais corrigé cette erreur suite aux erreurs que m'a montré tpierron!


Et apres avoir change, ca marche toujours pas? A priori ca devrait, vu que ce qui se passait c'est que dans ta methode nb_voisins, tu affectais un "0" a tous les voisins de la cellule... Verifies que t'en a pas oublie.

 

Sinon, une fois que t'auras regle ce probleme, je pense que ton algo sera toujours faux, mais ca sera plus fourbe. En effet, tu parcours la matrice en la rafraichissant dynamiquement, et tu reutilises immediatement les nouvelles valeurs pour faire evoluer d'autres cellules. Ce qui veut dire que tu ne calcules pas la nouvelle generation en te basant sur l'ancienne, mais plutot en te basant sur un mix de l'ancienne et de la nouvelle. En details:
- ta premiere "nouvelle" cellule aura ses 8 voisins de la generation precedente, et tu la feras evoluer correctement
- ta seconde cellule par contre n'aura que 7 voisins de la generation precedente, alors que le 8eme (celui que tu as deja fait evoluer) aura peut-etre deja change de valeur, et du coup tu ne vas pas calculer la seconde cellule corectement
- pareil pour toute la premiere ligne de la matrice, sauf la derniere cellule de la ligne ou deux des voisins n'auront plus leur valeur originale (a cause du tore)
- seconde ligne, ca s'empire: la premiere cellule a trois voisins (les trois de la premiere ligne) qui ont deja change, le reste de la ligne en aura quatre et la derniere cellule de la ligne cinq
- pareil jusqu'a la ligne 10 ou ca devient la fete du slip: a cause du tore, t'as de base 6 voisins qui ont deja evolue au debut de la ligne, puis 7, et bingo pour la derniere cellule qui aura ses 8 voisins deja evolues.

 

Je peux me tromper mais a mon avis, tu dois baser toute ta nouvelle generation sur l'ancienne - en gros, avoir un mecanisme qui te permet d'acceder pour chaque cellule a la valeur de l'ancienne generation, au moins jusqu'a ce que tu aies calcule la nouvelle entierement, moment a partir duquel les anciennes valeurs n'ont plus d'importance.

 

Edit: pour appuyer mes dires: si tu prends une meme matrice de depart, avec tes methodes, le resultat va etre different selon ton sens de parcours de la matrice, ce qui n'est pas normal.


Message édité par lasnoufle le 17-10-2013 à 03:23:34

---------------
C'était vraiment très intéressant.
Reply

Marsh Posté le 17-10-2013 à 11:47:40    

Citation :

Sinon, une fois que t'auras regle ce probleme, je pense que ton algo sera toujours faux, mais ca sera plus fourbe.

Bien vu, ça.
La correction est simple a faire, s'il ajoute un 2e tableau, qui contient le nb de voisins au lieu de faire un calcul dynamique.
 
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 17-10-2013 à 11:47:40   

Reply

Marsh Posté le 17-10-2013 à 15:26:57    

Il devrait faire 2 buffers (matrices), chacun représentant une génération et un pointeur qui, une fois sur 2 (ie, un tour de boucle sur 2), pointe sur l'un ou l'autre, un peu comme on fait dans les jeux vidéo avec le double buffering ;)


Message édité par rufo le 17-10-2013 à 15:27:19

---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed