INFORMATIQUE

TP 7

Jeu de George Noël


1. Présentation du jeu de George Noël
Il s'agit d'un jeu de stratégie à 2 joueurs. Le jeu ressemble au Master Mind® en ce sens qu'il faut découvrir une combinaison secrète à 5 chiffres.
Le premier joueur choisit un nombre à 5 chiffres. Ce nombre est la combinaison secrète que l'autre joueur devra découvrir.
Le second joueur fait des propositions successives de nombres à 5 chiffres, jusqu'à ce qu'il trouve la bonne combinaison ou que le nombre maximum d'essais autorisés est atteint. On peut fixer ce nombre maximum à 15 par exemple. Après chaque essai, le premier joueur fournit 2 indications :

Voici un début de partie où la combinaison secrète est 5 6 8 3 3

Combinaison secrète :   5 6 8 3 3   Trop petits    Trop grands
Essai n° 1 :            1 2 3 4 5       3              2
Essai n° 2 :            3 4 5 1 2       5              0

Etc... l'objectif étant de trouver la bonne réponse en faisant le moins d'essais possible.

2. Mise en place des composants

Dans la fiche principale, placer 2 composants StringGrid et 4 boutons.

Voici les propriétés de ces composants :

Fiche principale Name fmGeorgeNoel
Caption Jeu de George Noël
Grille 1 Name grEssais
Font Arial, gras, noir, taille 11
ColCount 6
RowCount 16
FixedCols 1
FixedRows 1
Options
Grille 2 Name grReponses
Font Arial, gras, bleu, taille 11
ColCount 2
RowCount 16
FixedCols 0
FixedRows 1
DefaultColWidth 90
Options Seules les 4 premières sont "true"
Bouton 1 Name btNouvellePartie
Caption &Nouvelle partie
Bouton 2 Name btAbandon
Caption &Abandon
Bouton 3 Name btQuitter
Caption &Quitter
Bouton 4 Name btOK
Caption &OK

Enregistrer tout en créant un nouveau répertoire, dans votre dossier :

Unit1.pas sous le nom uGeorgeNoel.pas
Project1.dpr sous le nom GeorgeNoel.dpr

3. Début d'une nouvelle partie

Sélectionner le bouton " Nouvelle partie " et, dans l'inspecteur d'objets, onglet événements, choisir l'événement On Click puis compléter le texte comme ci-dessous :

var
   fmGeorgeNoel: TfmGeorgeNoel;
   NumeroEssai : byte;
   Combinaison : array[1..5] of 0..9; //Tableau contenant les 5 chiffres à trouver

implementation

{$R *.DFM}

procedure TfmGeorgeNoel.btNouvellePartieClick(Sender: TObject);
var k : byte;
begin
   with grEssais do
   begin
      for k:=0 to 6 do cols[k].clear; //Effacement des 7 colonnes
      for k:=1 to 15 do cells[0,k]:=inttostr(k); //On remplit la colonne 0
      for k:=1 to 5 do cells[k,0]:=chr(64+k);
      //On remplit la ligne 0 avec les lettres A,B,C,D,E de codes 65,66,67,68,69
      randomize; //initialisation du générateur de nombres aléatoires
      for k:=1 to 5 do Combinaison[k]:=trunc(10*random);
      //Fabrication de la combinaison secrète
   end;
   with grReponses do
   begin
      for k:=0 to 1 do cols[k].clear;
      cells[0,0]:='Trop petits';
      cells[1,0]:='Trop grands';
   end;
   NumeroEssai:=1; //n° du prochain essai
   btOK.Enabled:=false;
end;

Pour que le lancement d'une nouvelle partie soit automatique au départ, il faut sélectionner l'événement OnActivate de la fiche fmGeorgeNoel et ajouter le code suivant :

procedure TfmGeorgeNoel.FormActivate(Sender: TObject);
begin
   btNouvellePartieClick(sender);
end;

4. Comment rendre le bouton OK accessible lorsque l'utilisateur a saisi son essai ?

Il faut faire en sorte que ce bouton ne soit accessible (propriété Enabled=true) uniquement lorsque l'utilisateur a saisi ses 5 chiffres, dans la bonne rangée !

Voici comment procéder (utiliser l'événement On KeyDown de la grille grEssai) :

procedure TfmGeorgeNoel.grEssaisKeyDown(Sender: TObject; var Key: Word;
           Shift: TShiftState);
var OK  : boolean;
    k,n : byte; //un byte est un entier compris entre 0 et 255
    err : integer;
    ch  : string;
begin
   OK:=true;
   with grEssais do for k:=1 to 5 do
   begin
      ch:=cells[k,NumeroEssai];
      val(ch,n,err);
      if (err>0)or(n>9) then OK:=false;
   end;
   btOK.Enabled:=OK;
end;

5. Réponse à un clic sur le bouton OK

Il s'agit de calculer le nombre de chiffres trop petits (de l'essai du joueur par rapport à la combinaison secrète) et le nombre de chiffres trop grands puis de les afficher dans la grille des réponses.

Le code ci-dessous se passe d'explications :

procedure TfmGeorgeNoel.btOKClick(Sender: TObject);
var k,TP,TG : byte;
begin
   TP:=0;TG:=0; //Mise à zéro des compteurs de chiffres
   with grEssais do
   for k:=1 to 5 do
   begin
      if StrToInt(cells[k,NumeroEssai])<Combinaison[k] then inc(TP);
      if StrToInt(cells[k,NumeroEssai])>Combinaison[k] then inc(TG);
   end;
   grReponses.Cells[0,NumeroEssai]:=IntToStr(TP);
   grReponses.Cells[1,NumeroEssai]:=IntToStr(TG);
   inc(NumeroEssai);
   grReponses.row:=NumeroEssai;
   btOK.Enabled:=false;
end;

6. Amélioration de l'affichage des grilles

Il est dommage que les composants StringGrid n'aient pas de propriété permettant de gérer l'alignement (centré ou à gauche ou à droite) dans chacune des cellules. Pour palier cet inconvénient, il faut utiliser le code suivant :

procedure TfmGeorgeNoel.grEssaisDrawCell(Sender: TObject; ACol,
            ARow: Integer; Rect: TRect; State: TGridDrawState);
var ch : string;
begin
   ch:=grEssais.cells[ACol,ARow];
   with grEssais.Canvas do
   begin
      brush.Style:=bsSolid;
      if (Acol=0)or(ARow=0) then brush.Color:=clSilver
                            else brush.color:=clWindow;
      if (Acol=0)or(ARow=0)
         then rectangle(rect.left,rect.top,rect.right,rect.bottom)
         else rectangle(rect.left-1,rect.top-1,rect.right+1,rect.bottom+1);
      brush.style:=bsClear;
      textout((rect.left+rect.right-textwidth(ch))div 2,
              (rect.top+rect.bottom-textheight(ch))div 2,ch);
   end;
end;

procedure TfmGeorgeNoel.grReponsesDrawCell(Sender: TObject; ACol,
             ARow: Integer; Rect: TRect; State: TGridDrawState);
var ch : string;
begin
   ch:=grReponses.cells[ACol,ARow];
   with grReponses.Canvas do
   begin
      brush.Style:=bsSolid;
      if (ARow=0) then brush.Color:=clSilver
                  else brush.color:=clWindow;
      if (ARow=0) then rectangle(rect.left,rect.top,rect.right,rect.bottom)
                  else rectangle(rect.left-1,rect.top-1,rect.right+1,rect.bottom+1);
      brush.style:=bsClear;
      textout((rect.left+rect.right-textwidth(ch))div 2,
              (rect.top+rect.bottom-textheight(ch))div 2,ch);
   end;
end;

7. Gestion des boutons Quitter et Abandon

Pour le bouton Quitter, pas de problème : faire comme d'habitude.
Pour le bouton Abandon : remplir les cellules de la ligne 0 de la grille grEssais avec les 5 chiffres du tableau Combinaison.

<< TP précédent      TP suivant >>

Retour à la liste des TP