Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Morpion] Mon code est il bien fait ?

Anonyme
    13 août 2017 à 14:14:26

    Bonjour j'ai créer un petit morpion pour m'entrainée après avoir appris le C . Seul petit problème j'ai l'impression que mon code est dégueulasse et est un peu bizarre . Je me demandais si des personnes pourraient me donner des conseils pour l'améliorer car j'ai beaucoup de problèmes que ce soit avec le programme ou le code de celui ci .

    Trucs dérangant :

    - Parfois lorsque je veux mettre un point (pion appeler comme vous le voudrez) sur la grille il ne fait plus rien , le programme ne réagit plus .

    - J'ai l'impression que je pourrais vérifier si l'on a gagné autrement et que ce que j'ai fait n'est pas une bonne façon

    - Je ne passe pas le tableau qui représente la grille en fonction j'ai une variable globale

    Morpion.h :

    char tab[3][3]; // Grille du morpion
    int i;
    int x;
    
    void displayGrid();
    void initializeGrid();
    int AiPlay();
    void gridModification(int line, int column);
    int checkWin();

    Morpion.c :

    #include <stdio.h>
    #include <stdlib.h>
    #include "Morpion.h"
    
    /**
    * Affiche la grille de morpion
    **/
    
    void displayGrid()
    {
        printf("\n\n\n");
        printf("+-----+\n");
        printf("|%c|%c|%c|\n", tab[0][0], tab[0][1], tab[0][2]);
        printf("+-----+\n");
        printf("|%c|%c|%c|\n", tab[1][0], tab[1][1], tab[1][2]);
        printf("+-----+\n");
        printf("|%c|%c|%c|\n", tab[2][0], tab[2][1], tab[2][2]);
        printf("+-----+\n");
        printf("\n\n\n");
    }
    
    /** 
    * Initialise la grille avec des espaces
    **/
    
    void initalizeGrid()
    {
    	for(i = 0; i < 3; i++)
    	{
    		for(x = 0; x < 3; x++)
    		{
    			tab[i][x] = ' ';
    		}
    	}
    }
    
    /** 
    * "Intelligence artificielle" qui met joue et pose des "O"
    **/
    
    int AiPlay()
    {
    	int line = (rand() % (2 - 0 + 1)) + 0;
    	int column = (rand() % (2 - 0 + 1)) + 0;
    	int founded = 0;
    	while(founded != 1) 
    	{
    		if(tab[line][column] == ' ')
    		{
    			tab[line][column] = 'O';
    			founded = 1;
    		}
    	}
    	return 1;
    }
    
    
    /** 
    * Poser sur la grille un X
    **/
    
    void gridModification(int line, int column)
    {
    	if(tab[line][column] == ' ')
    	{
    		tab[line][column] = 'X';
    	}
    	else 
    	{
    		printf("Emplacement invalide");
    	}
    }
    
    /**
    * Vérifie si vous avez gagnez la partie
    **/
    
    int checkWin()
    {
    	if(tab[0][0] == 'X' && tab[0][1] == 'X' && tab[0][2] == 'X')
    		return 1;
    	else if(tab[1][0] == 'X' && tab[1][1] == 'X' && tab[1][2] == 'X')	
    		return 1;
    	else if(tab[2][0] == 'X' && tab[2][1] == 'X' && tab[2][2] == 'X')
    		return 1;
    	else if(tab[0][0] == 'X' && tab[1][1] == 'X' && tab[2][2] == 'X')
    		return 1;
    	else if(tab[0][2] == 'X' && tab[1][1] == 'X' && tab[2][0] == 'X')
    		return 1;
    	else if(tab[0][0] == 'X' && tab[1][0] == 'X' && tab[2][0] == 'X')
    		return 1;
    	else if(tab[0][1] == 'X' && tab[1][1] == 'X' && tab[2][1] == 'X')
    		return 1;
    	else if(tab[0][2] == 'X' && tab[1][2] == 'X' && tab[2][2] == 'X')
    		return 1;
    
    
    	else if(tab[0][0] == 'O' && tab[0][1] == 'O' && tab[0][2] == 'O')
    		return -1;
    	else if(tab[1][0] == 'O' && tab[1][1] == 'O' && tab[1][2] == 'O')	
    		return -1;
    	else if(tab[2][0] == 'O' && tab[2][1] == 'O' && tab[2][2] == 'O')
    		return -1;
    	else if(tab[0][0] == 'O' && tab[1][1] == 'O' && tab[2][2] == 'O')
    		return -1;
    	else if(tab[0][2] == 'O' && tab[1][1] == 'O' && tab[2][0] == 'O')
    		return -1;
    	else if(tab[0][0] == 'O' && tab[1][0] == 'O' && tab[2][0] == 'O')
    		return -1;
    	else if(tab[0][1] == 'O' && tab[1][1] == 'O' && tab[2][1] == 'O')
    		return 1;
    	else if(tab[0][2] == 'O' && tab[1][2] == 'O' && tab[2][2] == 'O')
    		return -1;
    
    	else
    		return 0;
    }
    

    Le main.c :

    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
    #include "Morpion/Morpion.h"
    
    int main()
    {
    	srand(time(NULL));
    	int isFinsih = 0;
    	int line;
    	int column;
    
    	initalizeGrid();
    	printf("=== Morpion ===\n\n\n");
    	while(isFinsih != 1) 
    	{
    		system("clear");
    		displayGrid(tab);
    		printf("Entrez la ligne : ");
    		scanf("%d", &line);
    		printf("Entrez la colonne : ");
    		scanf("%d", &column);
    		gridModification(line, column);
    		int r = checkWin();
    		if(r == 1)
    		{
    			printf("You win !\n");
    			displayGrid();
    			isFinsih = 1;
    			return EXIT_SUCCESS;
    		}
    		AiPlay();
    		int v = checkWin();
    		if(v == -1)
    		{
    			printf("You lose :(\n");
    			displayGrid();
    			isFinsih = 1;
    			return EXIT_SUCCESS;
    		}
    	}
    
    	return 0;
    }

    Alors voila , je ne demande du code tout cuit mais juste de quoi m'aider à créer quelque chose de propre et qui fonctionne avec des conseils .

    Merci :=)


    -
    Edité par Anonyme 13 août 2017 à 14:15:23

    • Partager sur Facebook
    • Partager sur Twitter
      13 août 2017 à 17:56:53

      Salut !

      Je pense que tu peux factoriser ta fonction checkwin.

      Tout d'abord, tu peux définir un :

      char signe[2] ={'X','O'};
      char retour[2] = {1,-1};

      Et ensuite tu fais un for(i=0;i<2;i++), et au lieu de tester que tab[1][0]=='X', tu testes ==signe[i]

      et return retour[i];

      Déjà, tu divises ta fonction par deux.

      Ensuite, tu peux également refaire des for à l'intérieur pour factoriser ça :

      if(tab[0][0] == 'X' && tab[0][1] == 'X' && tab[0][2] == 'X')
              return 1;
          else if(tab[1][0] == 'X' && tab[1][1] == 'X' && tab[1][2] == 'X')  
              return 1;
          else if(tab[2][0] == 'X' && tab[2][1] == 'X' && tab[2][2] == 'X')
              return 1;

      En ça :

      for(j=0;j<3;j++)
      {
      if(tab[j][0] == signe[i] && tab[j][1] == signe[i] && tab[j][2] == signe[i])
              return retour[i];
      }

      Pareil pour les colonnes. 


      ça doit donner un truc comme ça :

      int checkWin()
      {
      	char signe[2] ={'X','O'};
      	char retour[2] = {1,-1};
      	int i,j;
      	for(i=0;i<3;i++)
      	{
      		for(j=0;j<3;j++)
      		{
      			if(tab[j][0] == signe[i] && tab[j][1] == signe[i] && tab[j][2] == signe[i])
      			        return retour[i];
      			if(tab[0][j] == signe[i] && tab[1][j] == signe[i] && tab[2][j] == signe[i])
      			        return retour[i];
      		}
         		if(tab[0][0] == signe[i] && tab[1][1] == signe[i] && tab[2][2] == signe[i])
      		        return retour[i];
      		if(tab[0][2] == signe[i] && tab[1][1] == signe[i] && tab[2][0] == signe[i])
      		        return retour[i];
      	}
              return 0;
      }



      -
      Edité par Fvirtman 13 août 2017 à 18:04:02

      • Partager sur Facebook
      • Partager sur Twitter

      Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

      Anonyme
        13 août 2017 à 18:07:41

        Fvirtman a écrit:

        Salut !

        Je pense que tu peux factoriser ta fonction checkwin.

        Tout d'abord, tu peux définir un :

        char signe[2] ={'X','O'};
        char retour[2] = {1,-1};

        Et ensuite tu fais un for(i=0;i<2;i++), et au lieu de tester que tab[1][0]=='X', tu testes ==signe[i]

        et return retour[i];

        Déjà, tu divises ta fonction par deux.

        Ensuite, tu peux également refaire des for à l'intérieur pour factoriser ça :

        if(tab[0][0] == 'X' && tab[0][1] == 'X' && tab[0][2] == 'X')
                return 1;
            else if(tab[1][0] == 'X' && tab[1][1] == 'X' && tab[1][2] == 'X')  
                return 1;
            else if(tab[2][0] == 'X' && tab[2][1] == 'X' && tab[2][2] == 'X')
                return 1;

        En ça :

        for(j=0;j<3;j++)
        {
        if(tab[j][0] == signe[i] && tab[j][1] == signe[i] && tab[j][2] == signe[i])
                return retour[i];
        }

        Pareil pour les colonnes. 



        -
        Edité par Fvirtman il y a 3 minutes


        J'ai pas trop compris pour les for dans la fonctions checkWin() . Par contre les variables globales c'est un problème ?
        • Partager sur Facebook
        • Partager sur Twitter
          14 août 2017 à 3:50:01

          Hello,

          Les variables globales évites les, surtout si c'est pour des variables de boucles. C'est pas propre.
          https://www.ltam.lu/cours-c/prg-c112.htm

          Pour ton bug il se trouve ici : 


          Tu boucles tant que "founded" n'est pas à 1. Sauf que si tu tombes sur autre chose qu'un espace, tu vas boucler à l'infinis (tu ne change jamais la ligne et la colonne si la case qu'il à tiré au hasard n'est pas un espace), rajoute un else.

          Dans ton main.c:


          Dans ton main tu boucles sur "isFinish", les seuls moment où tu passes ta variable à 1 pour sortir de la boucle, tu "return" directement, donc le "return 0" n'est jamais atteint.

          Pas propre non plus d'initialiser un variable à chaque tour de boucle :euh:.

           > J'ai pas trop compris pour les for dans la fonctions checkWin() . Par contre les variables globales c'est un problème ?

          En gros il parcourt toutes les lignes / colonnes puis les deux diagonales. Sauf qu'il vas avoir un "invalid write" à cause de son "for(i=0;i<3;i++)" parce que visiblement le tabeau n'as que deux élément et pas trois. :-° (ça arrive).




          Tu pourrais encore un peu plus "simplifier" en nombre de lignes en partant du code de Fvirtman, du genre : 

          int checkWin()
          {
              char signe[2] ={'X','O'};
              int i, j;
              for(i=0; i<2; i++)
              {
                  for(j=0; j<3; j++)
                  {
                      if ((tab[j][0] == signe[i] && tab[j][1] == signe[i] && tab[j][2] == signe[i]) ||
                          (tab[0][j] == signe[i] && tab[1][j] == signe[i] && tab[2][j] == signe[i]))
                              return (signe[i] == 'X' ? 1 : -1);
                  }
                  if ((tab[0][0] == signe[i] && tab[1][1] == signe[i] && tab[2][2] == signe[i]) ||
                      (tab[0][2] == signe[i] && tab[1][1] == signe[i] && tab[2][0] == signe[i]))
                              return (signe[i] == 'X' ? 1 : -1);;
              }
              return 0;
          }



          • Partager sur Facebook
          • Partager sur Twitter
          "Skill will accomplish what is denied to force" (Mertvago,1995)
          Anonyme
            14 août 2017 à 12:50:54

            Hey , merci beaucoup @venom0218 ! Donc ducoup je doit prévoire mes fonctions pour qu'ellent recoivent un tableau en paramètre ? Sinon je vais corriger tout ça p:

            -
            Edité par Anonyme 14 août 2017 à 13:00:19

            • Partager sur Facebook
            • Partager sur Twitter
              14 août 2017 à 14:17:38

              Asstryfi a écrit:

              Hey , merci beaucoup @venom0218 ! Donc ducoup je doit prévoire mes fonctions pour qu'ellent recoivent un tableau en paramètre ? Sinon je vais corriger tout ça p:

              -
              Edité par Asstryfi il y a environ 1 heure


              Disons que dans les "best practices", oui.
              Après ici, dans ton cas, tu utilises le tableau dans toutes tes fonctions donc c'est déjà plus "logique" d'avoir ton tableau en global.

              Par contre, pour les variables d’itérations "x,i", là sans aucun doute, il vaudrait mieux que tu les aient dans le corps de ta fonction.

              Imaginons que tu ais un programme multi-thread, il suffit que 2 thread bouclent avec les mêmes variables d'itérations et tu vas vite atteindre la fin de la boucle (si il s'agit d'un incrémenteur ++) puisque ils vont incrémenté simultanément la même variable 'globale', ratant ainsi des éléments du tableau. (Je sais pas si j'ai été très clair :euh:)

              • Partager sur Facebook
              • Partager sur Twitter
              "Skill will accomplish what is denied to force" (Mertvago,1995)
                14 août 2017 à 14:48:02

                venom0218 a écrit:

                Imaginons que tu ais un programme multi-thread, il suffit que 2 thread bouclent avec les mêmes variables d'itérations et tu vas vite atteindre la fin de la boucle (si il s'agit d'un incrémenteur ++) puisque ils vont incrémenté simultanément la même variable 'globale', ratant ainsi des éléments du tableau. (Je sais pas si j'ai été très clair :euh:)

                https://en.wikipedia.org/wiki/Race_condition
                • Partager sur Facebook
                • Partager sur Twitter
                  14 août 2017 à 16:19:54

                  NeitheryouNorme a écrit:

                  venom0218 a écrit:

                  Imaginons que tu ais un programme multi-thread, il suffit que 2 thread bouclent avec les mêmes variables d'itérations et tu vas vite atteindre la fin de la boucle (si il s'agit d'un incrémenteur ++) puisque ils vont incrémenté simultanément la même variable 'globale', ratant ainsi des éléments du tableau. (Je sais pas si j'ai été très clair :euh:)

                  https://en.wikipedia.org/wiki/Race_condition

                  @venom0218
                  @NeitheryouNorme

                  Rien à voir ...
                  Que la variable soit en global ou non, cela n'as rien à voir.
                  Quand une variable est utilisée par plusieurs threads, qu'elle soit global ou non, on la protège avec un mutex.

                  Maintenant, clairement, mettre des variables en global feront qu'elles seront par défaut accessible dans les deux threads.
                  Si ce sont des variables utilisées pour parcourir un tableau, on se rends compte à quel point c'est incohérent (pour ne pas dire stupide) d'avoir ce type de variable en global.

                  Une variable globale, si on est pas capable d'expliquer clairement pourquoi on la met en global, alors on ne la mets pas en globale.
                  Sinon c'est un nid a emmerde comme pas quatre.

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Anonyme
                    14 août 2017 à 17:21:33

                    SofEvans a écrit:

                    NeitheryouNorme a écrit:

                    venom0218 a écrit:

                    Imaginons que tu ais un programme multi-thread, il suffit que 2 thread bouclent avec les mêmes variables d'itérations et tu vas vite atteindre la fin de la boucle (si il s'agit d'un incrémenteur ++) puisque ils vont incrémenté simultanément la même variable 'globale', ratant ainsi des éléments du tableau. (Je sais pas si j'ai été très clair :euh:)

                    https://en.wikipedia.org/wiki/Race_condition

                    @venom0218
                    @NeitheryouNorme

                    Rien à voir ...
                    Que la variable soit en global ou non, cela n'as rien à voir.
                    Quand une variable est utilisée par plusieurs threads, qu'elle soit global ou non, on la protège avec un mutex.

                    Maintenant, clairement, mettre des variables en global feront qu'elles seront par défaut accessible dans les deux threads.
                    Si ce sont des variables utilisées pour parcourir un tableau, on se rends compte à quel point c'est incohérent (pour ne pas dire stupide) d'avoir ce type de variable en global.

                    Une variable globale, si on est pas capable d'expliquer clairement pourquoi on la met en global, alors on ne la mets pas en globale.
                    Sinon c'est un nid a emmerde comme pas quatre.

                    Et le mien est un bon cas ?
                    • Partager sur Facebook
                    • Partager sur Twitter
                      14 août 2017 à 17:50:59

                      Asstryfi a écrit:

                      Et le mien est un bon cas ?

                      Relis attentivement.

                      SofEvans a écrit:

                      Si ce sont des variables utilisées pour parcourir un tableau, on se rends compte à quel point c'est incohérent (pour ne pas dire stupide) d'avoir ce type de variable en global.

                      • Partager sur Facebook
                      • Partager sur Twitter
                      Anonyme
                        14 août 2017 à 17:53:24

                        DonneurDelecon2 a écrit:

                        Asstryfi a écrit:

                        Et le mien est un bon cas ?

                        Relis attentivement.

                        SofEvans a écrit:

                        Si ce sont des variables utilisées pour parcourir un tableau, on se rends compte à quel point c'est incohérent (pour ne pas dire stupide) d'avoir ce type de variable en global.

                        Ok , j'avais essayer de le faire au début mais je n'arrive pas a passer un tableau multidimensionel en paramètres .

                        • Partager sur Facebook
                        • Partager sur Twitter
                          14 août 2017 à 19:31:49

                          @Asstryfi

                          Tu me demandes si ton cas est un bon cas pour l'utilisation d'une variable globale.
                          Je te réponds que tu prends les chose dans le mauvais sens :
                          Ce n'est pas à moi de dire si tu peux utiliser une VG (variable globale), c'est à toi de justifier pourquoi tu utilises une VG.

                          Petit indice :
                          Hormis les cas où tu es obligé d'utiliser une VG (gestion des signaux, callback imposé style qsort,  ...), tu ne dois pas utiliser de VG.
                          Bon ok, y'a peut-être des exceptions comme une bibliothèque d’envois de log (un log peut s'envoyer de partout, et s'il faut des infos au préalable, alors on passe par une VG), mais généralement, VG = NON.

                          Quand tu auras suffisamment codé, tu sauras capable de distinguer quand tu dois utiliser une VG.
                          Mais pour le moment, c'est plus de la fainéantise qu'autre chose.
                          Et surtout, ca peut amener des bug difficile à tracer logiquement.

                          (edit : remplacement de VA par VG)

                          -
                          Edité par SofEvans 15 août 2017 à 13:38:34

                          • Partager sur Facebook
                          • Partager sur Twitter
                            15 août 2017 à 6:45:27

                            Ça veut dire quoi, « VA » ?

                            • Partager sur Facebook
                            • Partager sur Twitter
                            Anonyme
                              15 août 2017 à 6:59:28

                              robun a écrit:

                              Ça veut dire quoi, « VA » ?

                              Je suppose variable globale, mais je trouve pas la traduction

                              • Partager sur Facebook
                              • Partager sur Twitter
                                15 août 2017 à 11:05:47

                                oui, c'est cela.

                                Et je viens de me rendre compte que ca aurait dû être VG ...
                                J'ai vraiment besoin de vacance ...
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  15 août 2017 à 13:18:46

                                  J'avais compris que c'était pour désigner une variable globale, mais je m'interrogeais sur la signification du V et du A. Donc en fait c'était juste une faute de frappe, OK.

                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  [Morpion] Mon code est il bien fait ?

                                  × 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.
                                  • Editeur
                                  • Markdown