Partage
  • Partager sur Facebook
  • Partager sur Twitter

[C#] Débutant sur TP plus/moins

    12 mai 2011 à 16:44:35

    Bonjour,

    J'ai suivi le cours : http://www.siteduzero.com/tutoriel-3-3 [...] -sur-net.html
    pour apprendre le C#.

    J'ai réussi le TP du jeu Plus/moins, et j'ai décidé de l'améliorer, en comptant le nombre d'essais, en demandant au joueur s'il veut rejouer, et en laissant un choix de la difficulté.

    Je voulais votre avis, sur ma manière de coder, histoire de savoir si je code bien, ou si j'ai des mauvaise méthodes.

    Voici le code :
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                bool play = true;
                while (play)
                {
                    int nombreEssais = 0;
                    bool over = false;
                    Random rand = new Random();
                    int secretNumber = 0;
                    int nombreMax = 0;
                    string difficulty;
    
                    Console.WriteLine("Bienvenue dans le jeu du Plus ou Moins !\n\n");
                    Console.WriteLine("=== Difficulte ? ===\n");
                    Console.WriteLine("1. Facile ( Chiffre entre 1 et 100 )");
                    Console.WriteLine("2. Moyen ( Chiffre entre 1 et 500 )");
                    Console.WriteLine("3. Difficile ( Chiffre entre 1 et 1 000 )");
                    Console.WriteLine("\nVotre choix ?");
    
                    do{
                        difficulty = Console.ReadLine();
                        switch (difficulty)
                        {
                            case "1":
                            {
                                nombreMax = 100;
                                secretNumber = rand.Next(101);
                                Console.WriteLine("___________________\n\n\nVous avez choisi la difficulté n°{0}.", difficulty);
                                Console.WriteLine("C'est parti ! Choisissez un nombre entre 1 et {0}.", nombreMax);
                            }
                            break;
    
                            case "2":
                            {
                                nombreMax = 500;
                                secretNumber = rand.Next(501);
                                Console.WriteLine("___________________\n\n\nVous avez choisi la difficulté n°{0}.", difficulty);
                                Console.WriteLine("C'est parti ! Choisissez un nombre entre 1 et {0}.", nombreMax);
                            }
                            break;
    
                            case "3":
                            {
                                nombreMax = 1000;
                                secretNumber = rand.Next(1001);
                                Console.WriteLine("___________________\n\n\nVous avez choisi la difficulté n°{0}.", difficulty);
                                Console.WriteLine("C'est parti ! Choisissez un nombre entre 1 et {0}.", nombreMax);
                            }
                            break;
    
                            default:
                            {
                                Console.WriteLine("Erreur. Ecrivez seulement 1, 2 ou 3 ...");
                            }
                            break;
                        }
    
                    } while (difficulty != "1" && difficulty != "2" && difficulty != "3");
    
                    // tant que le jeu n'est pas fini (game over, vous savez !)
                    while (!over)
                    {
                        nombreEssais++;
                        string inputString = Console.ReadLine();
                        int inputNumber;
    
                        // si la conversion a marché
                        if (int.TryParse(inputString, out inputNumber))
                        {
                            // si c'est en dehors des limites
                            if (inputNumber < 0 || inputNumber > nombreMax)
                            {
                                Console.WriteLine("Veuillez entrer un nombre compris entre 1 et {0} (inclus).", nombreMax);
                            }
    
                            // si c'est le bon
                            else if (inputNumber == secretNumber)
                            {
                                Console.WriteLine("Vous avez gagné en {0} essai(s) !", nombreEssais);
                                Console.WriteLine("Vous avez gagné ! Le nombre mystère était: {0}.\n\n", secretNumber);
                                Console.WriteLine("Voulez vous rejouer ? oui/non");
                                string newGame;
                                do
                                {
                                    newGame = Console.ReadLine();
                                    if (newGame == "oui")
                                    {
                                        Console.WriteLine("C'est reparti pour un tour !! :D\n\n");
                                    }
                                    else if (newGame == "non")
                                    {
                                        play = false;
                                        Console.WriteLine("Très bien, on s'arrête là pour aujourd'hui ! A bientot :)");
                                    }
                                    else
                                    {
                                        Console.WriteLine("Erreur. Ecrivez seulement oui ou non.");
                                    }
                                }
                                while (newGame != "oui" && newGame != "non");
                                over = true;
                            }
    
                            // si c'est trop petit
                            else if (inputNumber < secretNumber)
                            {
                                Console.WriteLine("C'est plus.");
                            }
    
                            // si c'est trop grand
                            else
                            {
                                Console.WriteLine("C'est moins.");
                            }
                        }
                        // si la conversion n'a pas réussi
                        else
                        {
                            Console.WriteLine("Une erreur est survenue lors de la conversion.");
                            Console.WriteLine("Veuillez entrer un nombre compris entre 1 et 100 (inclus).");
                        }
                    }
                }
    
                // Cela permet de marquer une pause à la fin: le programme attend que vous appuyez sur Entrée et va récupérer ce que vous avez écrit.
                // Ici, le résultat de la fonction n'est pas utilisé: on n'affecte aucune variable avec.
                // On utilise donc la fonction comme si elle rendait void.
                Console.ReadLine();
    
            }
        }
    }
    


    Merci d'avance :)
    • Partager sur Facebook
    • Partager sur Twitter
      12 mai 2011 à 16:53:38

      Tu devrais éviter de tout faire dans ton Main comme ça. Fais plutôt une méthode "Play", une méthode "AskForDifficulty" qui te renvois le nombre, etc... Sa rendait ton code beaucoup plus lisible et facilement modifiable.

      De plus, si tu fais toutes tes méthodes dans une classe à part, il te serais possible par la suite d'utiliser cette classe pour faire un jeu en changeant l'IHM (en passant de la console à du web ou du WPF par exemple)
      • Partager sur Facebook
      • Partager sur Twitter
      Anonyme
        12 mai 2011 à 17:07:04

        Quelques remarques :
        • Tu mélanges français et anglais dans les noms de variables, je te conseille fortement de tout faire en anglais.
        • Tes commentaires sont, pour la plupart, inutiles. Par exemple, "si la conversion a marché" dans un if(int.TryParse(...)) c'est limite, mais en plus "si la conversion n'a pas marché" dans le else, ça ne sert à rien.
        • Essaie de réduire les niveaux d'indentation nécessaires. Par exemple, au lieu de ça :
          if (int.TryParse(inputString, out inputNumber))
          {
              // du code ici
          }
          else
          {
              Console.WriteLine("Une erreur est survenue lors de la conversion.");
              Console.WriteLine("Veuillez entrer un nombre compris entre 1 et 100 (inclus).");
          }
          

          Utilise ça :
          if(!int.TryParse(inputString, out inputNumber))
          {
              Console.WriteLine("Une erreur est survenue lors de la conversion.");
              Console.WriteLine("Veuillez entrer un nombre compris entre 1 et 100 (inclus).");
              continue; // revenir au début du while en réévaluant la condition
          }
          // du code ici
          

          Le conseil de Mangepain te permettra aussi d'éviter trop d'indentation et de mieux structurer ton code ^^
        • Tu peux éviter d'utiliser la variable play et simplement faire un while(true). Utilise ensuite break pour en sortir si l'utilisateur ne souhaite pas rejouer.
        • Tu peux éviter d'avoir à tester la limite inférieure en utilisant un uint, ou int non signé (donc toujours positif). uint.TryParse(...) renvoie false si le string est un nombre plus petit que zéro.

        • Partager sur Facebook
        • Partager sur Twitter
          12 mai 2011 à 17:22:53

          Mangepain a raison en te conseillant de créer des fonctions qui vont permettre d'alléger ta fonction Main. Idéalement on devrait pouvoir comprendre l'organisation d'une fonction en deux secondes maximum avec un oeil expérimenté - et actuellement ça prend au moins 30 secondes, ce qui est donc beaucoup trop ;)

          Il y a deux types de fonction:
          - les fonctions qui regroupent une fonctionnalité du programme; par exemple comme l'a dit MangePain une fonction AskForDifficulty() qui s'occupe de... eh bien... demander le niveau de difficulté :p L'idée c'est que si dans ton Main on voit difficulty = AskForDifficulty(); on comprend directement que cette partie s'occupe de cet aspect. Et c'est suffisant, on n'a pas besoin de voir immédiatement en quoi ça consiste en lisant le Main: on veut juste une vue "hélicoptère".
          - les fonctions "utilitaires" qui servent surtout à éviter les répétitions de code. Par exemple à deux reprises dans ton code tu demandes à l'utilisateur de faire un choix parmi une liste de choix possibles ([1,2,3] et [oui,non]). Tu peux faire une fonction AskChoice qui fera ça pour toi en gérant la boucle while, le message d'erreur et compagnie, et que tu n'auras plus qu'à appeler à deux reprises ;)

          Je ne suis cependant pas d'accord avec l'idée de Mangepain de séparer la présentation et la logique métier. On est dans un cas où la couche d'abstraction nécessaire pèserait plus lourd que la couche de logique métier elle-même, donc ce n'est pas justifié.

          Je ne suis pas d'accord non plus avec la suggestion d'Aethec d'utiliser des break et des continue: dans la mesure du possible, mieux vaut avoir un et un seul point de sortie pour chaque bloc d'instructions. ;)
          • Partager sur Facebook
          • Partager sur Twitter
            12 mai 2011 à 19:04:55

            Merci à tous.

            Donc niveau séparation des fonctions / créations de classes en plus, j'avais pas pensé à ca, car c'est vraiment un petit truc donc bon... J'y penserais pour la prochaine fois.

            Au niveau de ta remarque sur les continue etc, moi j'ai fais mon code, et ensuite j'ai copié collé celui de la correction du TP, puis j'ai appliqué les améliorations, donc pour moi le code était optimisé...

            Merci encore :)

            Je vais voir si j'ai le temps d'ajouter des fonctions/méthodes à ce mini prog.
            • Partager sur Facebook
            • Partager sur Twitter
            Anonyme
              12 mai 2011 à 19:18:35

              Disons que la séparation est une bonne chose, mais pour un aussi petit logiciel c'est pas forcément plus efficace.
              Par contre, dès que tu fais des logiciels avec une interface graphique ou une récupération de données quelque part (genre base de données) il te faut absolument séparer la récupération des données (couche "bête" qui lit les données sans savoir ce qu'on en fait et les renvoie dans un format acceptable), l'interface graphique (couche "bête" qui affiche ce qu'on lui demande sans savoir ce que c'est) et les méthodes "intelligentes" dans lesquelles il y a de la vraie logique.
              De cette façon, tu peux changer d'interface graphique ou de source de données sans avoir à réécrire le programme en entier.

              Pour te donner un (petit) exemple, j'ai récemment converti un jeu de Snake que j'avais fait en WPF depuis WinForms. Vu que mon code était séparé correctement, il m'a suffit de modifier les méthodes qui touchaient au dessin du serpent dans la fenêtre, je n'ai pas eu à modifier les autres méthodes (du genre celle qui détermine si le serpent meurt au prochain mouvement).
              • Partager sur Facebook
              • Partager sur Twitter

              [C#] Débutant sur TP plus/moins

              × 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