Aller au menu - Aller au contenu

Icône TP : le jeu du plus ou du moins

Mise à jour : 02/02/2012
Difficulté : Facile Facile Creative Commons BY-NC-SA
22 955 visites depuis 7 jours, dont 192 sur ce chapitre classé 15/786
Wahou, nous augmentons régulièrement le nombre de choses que nous savons. C'est super. Nous commençons à être capables d'écrire des applications qui ont un peu plus de panache !

Enfin… moi, j'y arrive ! Et vous ? C'est ce que nous allons vérifier avec ce TP.

Savoir interagir avec son utilisateur est important. Voici donc un petit TP sous forme de création d'un jeu simple qui va vous permettre de vous entraîner. L'idée est de réaliser le jeu classique du plus ou du moins…
Sommaire du chapitre :
Icône du chapitre
Chapitre précédent Sommaire Chapitre suivant

Instructions pour réaliser le TP

Je vous rappelle les règles. L’ordinateur nous calcule un nombre aléatoire et nous devons le deviner. À chaque saisie, il nous indique si le nombre saisi est plus grand ou plus petit que le nombre à trouver. Une fois trouvé, il nous indique en combien de coups nous avons réussi à trouver le nombre secret.

Pour ce TP, vous savez presque tout faire. Il ne vous manque que l’instruction pour obtenir un nombre aléatoire. La voici, cette instruction permet de renvoyer un nombre compris entre 0 et 100 (exclu). Ne vous attardez pas trop sur sa syntaxe, nous aurons l’occasion de comprendre exactement de quoi il s’agit dans le chapitre suivant :

Code : C#
1
int valeurATrouver = new Random().Next(0, 100);


Le principe est grosso modo le suivant : tant qu’on n’a pas trouvé la bonne valeur, nous devons en saisir une nouvelle. Dans ce cas, la console nous indique si la valeur est trop grande ou trop petite. Il faudra bien sur incrémenter un compteur de coups à chaque essai.

N’oubliez pas de gérer le cas où l’utilisateur saisit n’importe quoi. Nous ne voudrions pas que notre premier jeu ait un bug qui fasse planter l’application !

Allez, je vous en ai trop dit. C’est à vous de jouer. Bon courage.

Correction

Voici ma correction de ce TP.

Bien sûr, il existe beaucoup de façon de réaliser ce petit jeu. S’il fonctionne, c’est que votre solution est bonne. Ma solution fonctionne, la voici :

Code : C#
 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
static void Main(string[] args)
{
    int valeurATrouver = new Random().Next(0, 100);
    int nombreDeCoups = 0;
    bool trouve = false;
    Console.WriteLine("Veuillez saisir un nombre compris entre 0 et 100 (exclu)");
    while (!trouve)
    {
        string saisie = Console.ReadLine();
        int valeurSaisie;
        if (int.TryParse(saisie, out valeurSaisie))
        {
            if (valeurSaisie == valeurATrouver)
                trouve = true;
            else
            {
                if (valeurSaisie < valeurATrouver)
                    Console.WriteLine("Trop petit ...");
                else
                    Console.WriteLine("Trop grand ...");
            }
            nombreDeCoups++;
        }
        else
            Console.WriteLine("La valeur saisie est incorrecte, veuillez recommencer ...");
    }
    Console.WriteLine("Vous avez trouvé en " + nombreDeCoups + " coup(s)");
}


On commence par obtenir un nombre aléatoire avec l’instruction que j’ai fournie dans l’énoncé. Nous avons ensuite les initialisations de variables. L’entier nombreDeCoups va permettre de stocker le nombre d’essai et le booléen « trouve » va permettre d’avoir une condition de sortie de boucle.

Notre boucle démarre et ne se terminera qu’une fois que le booléen « trouve » sera passé à vrai (true).
Dans le corps de la boucle, nous demandons à l’utilisateur de saisir une valeur que nous essayons de convertir en entier. Si la conversion échoue, nous l’indiquons à l’utilisateur et nous recommençons notre boucle. Notez ici que je n’incrémente pas le nombre de coups, jugeant qu’il n’y a pas lieu de pénaliser le joueur parce qu’il a mal saisi ou qu’il a renversé quelque chose sur son clavier juste avant de valider la saisie.

Si par contre la conversion se passe bien, nous pouvons commencer à comparer la valeur saisie avec la valeur à trouver. Si la valeur est la bonne, nous passons le booléen à vrai, ce qui nous permettra de sortir de la boucle et de passer à la suite. Sinon, nous afficherons un message pour indiquer si la saisie est trop grande ou trop petite en fonction du résultat de la comparaison.
Dans tous les cas, nous incrémenterons le nombre de coups.

Enfin, en sortie de boucle, nous indiquerons sa victoire au joueur ainsi que le nombre de coups utilisés pour trouver le nombre secret.
Une partie de jeu pourra être :

Image utilisateur

Aller plus loin

Il est bien sûr toujours possible d’améliorer le jeu. Nous pourrions par exemple ajouter un contrôle sur les bornes de la saisie. Ainsi, si l’utilisateur saisit un nombre supérieur ou égal à 100 ou inférieur à 0, nous pourrions lui rappeler les bornes du nombre aléatoire.

De même, à la fin, plutôt que d’afficher « coup(s) », nous pourrions tester la valeur du nombre de coups. S’il est égal à 1, on affiche « coup » au singulier, sinon « coups » au pluriel.

La boucle pourrait également être légèrement différente. Plutôt que de tester la condition de sortie sur un booléen, nous pourrions utiliser le mot clé break. De même, nous pourrions alléger l’écriture avec le mot clé continue.

Par exemple :

Code : C#
 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
static void Main(string[] args)
{
    int valeurATrouver = new Random().Next(0, 100);
    int nombreDeCoups = 0;
    Console.WriteLine("Veuillez saisir un nombre compris entre 0 et 100 (exclu)");
    while (true)
    {
        string saisie = Console.ReadLine();
        int valeurSaisie;
        if (!int.TryParse(saisie, out valeurSaisie))
        {
            Console.WriteLine("La valeur saisie est incorrecte, veuillez recommencer ...");
            continue;
        }
        if (valeurSaisie < 0 || valeurSaisie >= 100)
        {
            Console.WriteLine("Vous devez saisir un nombre entre 0 et 100 exclu ...");
            continue;
        }
        nombreDeCoups++;
        if (valeurSaisie == valeurATrouver)
            break;
        if (valeurSaisie < valeurATrouver)
            Console.WriteLine("Trop petit ...");
        else
            Console.WriteLine("Trop grand ...");
    }
    if (nombreDeCoups == 1)
        Console.WriteLine("Vous avez trouvé en " + nombreDeCoups + " coup");
    else
        Console.WriteLine("Vous avez trouvé en " + nombreDeCoups + " coups");
}


Tout ceci est une question de goût. Je préfère personnellement la version précédente n’aimant pas trop les break et les continue. Mais après tout, chacun fait comme il préfère, l’important est que nous amusions à écrire le programme et à y jouer. :D
Voilà, ce TP est terminé.

Vous avez pu voir finalement que nous étions tout à fait capables de réaliser des petites applications récréatives. Personnellement, j'ai commencé à m'amuser à faire de la programmation en réalisant toute sorte de petits programmes de ce genre.

Je vous encourage fortement à essayer de créer d'autres programmes vous-mêmes, pourquoi pas à proposer aux autres vos idées.
Plus vous vous entraînerez à faire des petits programmes simples et plus vous réussirez à appréhender les subtilités de ce que nous avons appris.

Bien sûr, plus tard, nous serons capables de réaliser des applications plus compliquées ... Cela vous tente ? Alors continuons la lecture. :)
Chapitre précédent Sommaire Chapitre suivant

Partager

20 commentaires pour "TP : le jeu du plus ou du moins"
Note moyenne : 3.05 / 4 (230 votes)
Pseudo Commentaire
Hors ligne Nihak Ben # Posté le 13/04/2012 à 10:30:27
Avatar

Avis : Très bon

Ma version. (Inspiré du Javascript :D )


Code : C#
 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
static void Main(string[] args)
        {
            int valeurATrouver = new Random().Next(0, 100);
            bool trouve = true;
            int nombre;
            int nombreDeCoups = 0;
            Console.WriteLine("Jeu : Trouver le nombre inconnu  entre 1 et 100. \n");
            
            while (trouve)
            {
                
                Console.WriteLine("Veuillez saisir votre nombre :");
                string saisie = Console.ReadLine();
                nombre = Convert.ToInt32(saisie);
                if (nombre > valeurATrouver)
                {
                    Console.WriteLine("C'est plus petit !");
                    nombreDeCoups++;
                }
                if (nombre < valeurATrouver) {
                    Console.WriteLine("C'est plus grand !");
                    nombreDeCoups++;
                }
                if (nombre == valeurATrouver)
                {
                    
                    trouve = false;
                }
            }
            if (nombreDeCoups == 1)
            Console.WriteLine("Bravo, vous avez trouvé " + valeurATrouver + " en " + nombreDeCoups + " coup !");
            else
                Console.WriteLine("Bravo, vous avez trouvé " + valeurATrouver + " en " + nombreDeCoups + " coups !");
        }
Hors ligne gfox78 # Posté le 17/04/2012 à 11:56:21
Avatar

Avis : Très bon

Ville : Marcq
Pays : France métropolitaine

Bonjour,
Je me suis bien amusé avec ce TP et j'y ai passé la journée pour ajouter quelques éléments qui m'ont permis d'explorer les références et exemples de la msdn library..
Voila ma version:
Secret (cliquez pour afficher)

Code : Autre
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
/**Recherche d'un entier aléatoire entre 0 et une "limite" maximale, tiré par l'ordinateur 
  *   Les erreurs de logique du joueur sont détectées.
  *   L'ordinateur le recherche automatiquement et compare son résultat avec la performance du joueur
  *   L'ordinateur donne sa performance moyenne pour résoudre ce  type de problème. */

// auteur: gfox78, 17/4/2012


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace JeuPlusMoins
{
    class Program
    {
        static double MoyenneNbcoups(int limite)
            // pour calculer la moyenne des coups nécessaires à l'ordinateur pour trouver le nombre
        {
            Random rnd = new Random(); 
            double sommeCoups = 0;
            int nbessai = 10000;                // nombre de répétitions pour calculer la moyenne
            for (int n = 0; n < nbessai; n++) sommeCoups += Automate(rnd.Next(0,limite), limite);           
            return sommeCoups / nbessai;
        }
               
        static int Automate(int valA, int limite)
            // L'ordinateur cherche automatiquement la solution de manière optimisée
        {
            int valAncMax = limite, valAncMin = 0, diff = 0,  maValeur = limite / 2;
            int nbCoups = 1;         
            
            while(maValeur != valA) 
            {            
                if (maValeur < valA)
                { 
                    diff = (maValeur - valAncMax) / 2; 
                    valAncMin = maValeur; 
                }
                else
                {
                    diff = (maValeur - valAncMin) / 2;
                    valAncMax = maValeur; 
                }
                maValeur -= diff;
                nbCoups++;
                if (diff == 0) maValeur--; // cas ou ValA = 0 et diff = 0
            }
            return (nbCoups); 
        }
           
        static int NbATrouver(int valA, int limite )
        {   // recherche manuelle de la solution
            int taValeur, nbCoups = 1;
            int diff, diffMaxMoins = -limite,  diffMaxPlus = limite;
            Console.Write("   Donnez votre nombre ("+ nbCoups+") : ");                    
            do
            {
                string svaleur = Console.ReadLine();
                string erreurLogique = "";
                if (int.TryParse(svaleur, out taValeur))
                {
                    if (taValeur < 0) return 100;   // en cas d'abandon
                    diff = taValeur - valA; 
                    if (diff < 0)
                    {                        
                        if (diff < diffMaxMoins) { erreurLogique = " ... erreur logique"; } else { diffMaxMoins = diff; }
                        Console.WriteLine("                                  trop petit !! "+ erreurLogique);
                    }
                    if (diff > 0)
                    {                        
                        if (diff > diffMaxPlus) { erreurLogique = " ... erreur logique"; } else { diffMaxPlus = diff; }
                        Console.WriteLine("                                  trop grand !! " + erreurLogique);
                    }
                    if (diff == 0)
                    {
                        Console.WriteLine("                                   C'EST BON !!  ");
                        return nbCoups++;
                    }
                }
                else
                {
                    Console.WriteLine("                                 entrée incorrecte, mais cela compte !");
                }
                nbCoups++;
                Console.Write("Donnez un autre nombre (" + nbCoups + ") : ");
            } while (valA != taValeur);
            return nbCoups;
        }

        static void Main(string[] args)
        {
            ConsoleKeyInfo reponse;
            int limite = 100; // pour faire varier l'étendue des nombres aléatoires choisis
            int tentativeJoueur, tentativeOrdi;
            string coup;
            string appreciation = "";
            Console.WriteLine("\nDonnez le nombre entier entre 0 et " + limite + " (exclu), tiré par l'ordinateur");
            Console.WriteLine("                  Donnez un nombre négatif pour abandonner.\n");
            do
            {
                int valeurAlea = new Random().Next(0, limite);
                // valeurAlea = 50; // pour mise au point
                // Console.Write("Valeur à trouver : " + valeurAlea );  // pour repérer un éventuel bug dans Automate.
                tentativeOrdi = Automate(valeurAlea, limite); // L'ordinateur cherche le nombre tout seul
                tentativeJoueur = NbATrouver(valeurAlea,limite);
               
                // commentaire sur les performances du joueur
                appreciation = "    Résultat honorable";   // mention par défaut
                if(tentativeJoueur < tentativeOrdi - 1) appreciation = "    Vous avez eu le \"nez fin\" !!!";
                if(tentativeJoueur > tentativeOrdi + 1) appreciation = "    Vous auriez sans doute pu faire mieux !!! ";
                switch (tentativeJoueur)
                {
                    case 1:  
                    case 2:
                        appreciation = "    VOUS ETES UN VEINARD !!! ";
                        break;
                    case 100:
                        appreciation = "    Vous êtes un PARESSEUX !!! ";                      
                        break;
                }    
 
                if (tentativeJoueur == 1) { coup = " coup"; } else { coup = " coups"; }
                if (tentativeJoueur < 100)
                {
                    Console.WriteLine("Vous avez trouvez " + valeurAlea + " en " + tentativeJoueur + coup + "\n" + appreciation);
                }
                else
                {
                    Console.WriteLine("Le résultat était " + valeurAlea + "\n" + appreciation);
                }                              
                Console.WriteLine("\nPour la valeur : "+ valeurAlea + ", l'ordinateur a réussi à le faire en " + tentativeOrdi + " coup(s)");
                Console.WriteLine(); 
                Console.WriteLine("Voulez-vous recommencer (O/N) ?");
                reponse = Console.ReadKey(true);              
            } while (reponse.Key == ConsoleKey.O);
            Console.WriteLine("En moyenne, l'ordinateur résoud ce type de problème en " + MoyenneNbcoups(limite) + " coups,");
            Console.WriteLine("                                                   sur 10000 essais");   
        }
    }
}


J'ai ajouté un système permettant de détecter les erreurs de logique de l'utilisateur.
Une routine 'automate' permet à l'ordinateur de rechercher lui-même le nombre aléatoire de manière optimisée. Cela permet de commenter les performances du jouer et de calculer une performance moyenne pour résoudre le problème posé.
Pour abandonner le jeu, je me suis contenté d'enter un nombre négatif: J'aurais voulu utiliser un 'ESC' mais je n'ai pas trouver de solution acceptable pour concilier Console.ReadLine et ConsoleKey. La solution aurait peut-être été d'utiliser Console.Read et 0x1B ?
Autre chose, comment jouer en aveugle, c'est à dire en évitant que le nombre introduit par le joueur soit affiché sur l'écran ?
Dernière question: la pratique du langage C m'a toujours incité à mettre le 'main' en fin de fichier alors que les exemples donnés placent le 'main' au début. Est-ce que c'est une pratique classique à respecter en C# ou simplement un choix laissé à la liberté du programmeur ?.
Hors ligne nico.pyright # Posté le 17/04/2012 à 12:58:06
Groupe : Auteurs

Salut,

tu peux faire un truc de ce genre :

Code : C#
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ConsoleKeyInfo touche;
Console.WriteLine("Veuillez saisir un nombre et validez par entrée (ESC pour quitter)");
string resultat = string.Empty;
while (true)
{
    touche = Console.ReadKey(true);
    if (touche.Key == ConsoleKey.Enter)
    {
        Console.WriteLine("Vous avez saisi : " + resultat);
        resultat = string.Empty;
        Console.WriteLine("Veuillez saisir un nombre et validez par entrée (ESC pour quitter)");
    }
    else
    {
        if (touche.KeyChar >= '0' && touche.KeyChar <= '9')
        {
            resultat += touche.KeyChar;
        }
        else if (touche.Key == ConsoleKey.Escape)
        {
            break;
        }
    }
}


Le soucis, c'est qu'il va falloir que tu gères la suppression avec backspace ou autre commodités. Et puis la saisie en aveugle, c'est bien pour une touche, mais pour une chaine, ca devient compliqué

Sinon, je n'ai pas de recommandation pour la méthode Main()
 
Hors ligne gfox78 # Posté le 19/04/2012 à 07:21:48
Avatar

Avis : Très bon

Ville : Marcq
Pays : France métropolitaine

Merci au groupe Auteur pour cette solution. Elle permet de combiner l'entrée du nombre et l'utilisation de ESC. Elle peut aussi résoudre le problème du jeu à l'aveugle.
Hors ligne Helgrind444 # Posté le 20/04/2012 à 15:38:01
Avatar

Avis : Très bon

Si vous voulez vous entraîner, vous pouvez essayer de faire un pile ou face. Ça devrait être plus simple que ce TP, normalement, on y arrive sans trop de mal :p
J'ai essayé de faire ça en respectant certaines conditions, mais il y a un point que je n'ai pas réussi...

Quelques conditions (sinon c'est trop simple) :
-> On devra appuyer sur une touche (L par exemple) pour lancer la pièce.
-> Possibilité de lancer la pièce plusieurs fois sans quitter la console.
-> Si on appuie sur Q, la console se ferme.


Ma correction personnelle (je sais pas si c'est optimisé... mais ça marche !).


Code : C#
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
static void Main(string[] args)
        {
            Console.WriteLine("Bienvenue sur Pile ou Face ! Pour quitter le jeu, appuyez sur \"Q\"");

            ConsoleKeyInfo saisie = Console.ReadKey(true);
            while (saisie.Key != ConsoleKey.Q)
            {
                Console.WriteLine("Appuie sur L pour (re)lancer la pièce !");
                ConsoleKeyInfo saisie2 = Console.ReadKey(true);
                if (saisie2.Key == ConsoleKey.L)
                {
                    int hasard = new Random().Next(1, 3);
                    if (hasard == 1)
                        Console.WriteLine("Pile " + hasard); // Le "+hasard" est là uniquement pour vérifier que ça marche, il n'est pas nécessaire et ne change absolument rien au code.
                    else
                        Console.WriteLine("Face " + hasard);
                }
                else
                    Console.WriteLine("Mauvaise touche.");
            }



Le seul problème avec ce code, c'est que l'on ne peut pas quitter...
J'avais pensé à rajouter un if, qui, si la touche était Q, faisait quitter la console, mais je ne connais pas la commande (je pense qu'il y en a une :p ).

Je sais mapper sur Source :D
HTML/CSS, c'est fait !
En route pour le C# !

Merci le SDZ ! :p
 

Voir tous les commentaires