Вы находитесь на странице: 1из 10

TD 5 : Un jeu de Tic tac toe1

Centre Informatique pour les Lettres et les Sciences Humaines

1 - Comment pourrait-on programmer a ?.............................................................................. 2 Choix des contrles......................................................................................................... 2 Alternance des marques.................................................................................................. 3 Remise du jeu dans son tat initial ................................................................................. 3 Dtection de la victoire ventuelle d'un des joueurs ........................................................ 3 2 - Cration du projet et dessin de l'interface ........................................................................... 3 3 - Ecriture du code................................................................................................................. 4 La fonction f_effacer() ................................................................................................ 4 Effacement des marques ........................................................................................ 4 Rendre toutes les cases utilisables ......................................................................... 4 Remettre zro les alignements ............................................................................. 5 Dsignation du joueur qui va commencer .............................................................. 5 Premire bauche d'une fonction associe un bouton "case"......................................... 6 Matrialisation du coup ......................................................................................... 6 Mise jour des alignements................................................................................... 6 En cas de victoire................................................................................................ 7 La fonction codeCommunATousLesCoups() ..................................................................... 7 Les fonctions associes aux boutons "case"..................................................................... 8 Cration du type EJoueur ............................................................................................... 8 La classe CAlignement ................................................................................................... 8 Cration de la classe .............................................................................................. 8 Cration des membres ........................................................................................... 9 La fonction reset() .............................................................................................. 9 La fonction ajouteMarque() ................................................................................. 9 Les variables membre de la classe TD05Dialog ............................................................... 9 4 - Questions ..........................................................................................................................10

Selon le Trsor de la Langue Franaise, le morpion est un "jeu qui consiste pour chacun des deux adversaires placer tour de rle un signe distinctif (croix ou cercle) sur du papier quadrill pour s'efforcer d'obtenir le plus rapidement une file continue de cinq signes dans n'importe quelle direction". C'est donc improprement que ce nom est parfois utilis pour dsigner le jeu limit neuf cases dont il est question ici. Bien qu'il sonne fcheusement anglo-saxon, le nom "tic tac toe" est bien plus usit que "OXO", le seul autre nom que je connaisse pour ce jeu. Document du 12/01/04

- Retrouvez la version la plus rcente sur

http://www.up.univ-mrs.fr/wcpp

VC++ 6.0 - Qt 2.3

TD 5 : tic tac toe

2/10

L'objectif du TD 05 est d'illustrer l'utilisation de fonctions dotes de paramtres. Le TD 05 offre en outre une occasion d'employer effectivement une classe cre spcialement pour reprsenter les donnes de notre problme (et non pour reprsenter un dialogue). Le programme servant de prtexte cette illustration permet deux utilisateurs d'employer l'ordinateur pour remplacer le sable habituellement utilis pour jouer un jeu de plage bien connu : il s'agit, sur un damier 3 x 3, de parvenir aligner trois marques identiques sur une ligne, une colonne ou une diagonale (chacun des joueurs utilise une marque diffrente, et ils choisissent tour tour une des cases encore libres pour y placer leur marque). Les joueurs placent simplement leur marque en cliquant sur la case choisie (le programme passe automatiquement d'une marque l'autre chaque coup jou). Lorsque l'un des joueurs parvient aligner trois de ses marques, un message annonant sa victoire est affich. Le bouton "Effacer" permet, tout moment, de commencer une nouvelle partie.

L'interface utilisateur du programme ralis au cours du TD 05

1 - Comment pourrait-on programmer a ?


Le cahier des charges esquiss ci-dessus rvle trois caractristiques essentielles du programme : - il doit tre capable de placer alternativement des ronds et des croix dans les cases sur lesquelles les utilisateurs cliquent ; - il doit tre capable de dtecter (et d'annoncer) la victoire ventuelle d'un des deux joueurs ; - il doit enfin tre capable de remettre le jeu dans son tat initial (les cases doivent tre vides). Choix des contrles Une des toutes premires dcisions prendre concerne la faon dont nous allons matrialiser les cases dans lesquelles se droule le jeu. Une premire faon de faire serait de disposer 9 multiLineEdit, ce qui nous permettrait de modifier le texte affich en employant l'oprateur d'insertion introduit lors du TD 4. Les cases du jeu ne servent toutefois pas qu' afficher les marques : elles doivent galement ragir lorsqu'un utilisateur clique dessus. Cette caractristique correspond plus la vocation d'un bouton qu' celle d'un multiLineEdit, ce qui suggre une seconde hypothse. Si les cases sont reprsentes par des boutons, nous n'aurons aucune difficult les faire ragir en cas de clic, mais nous allons devoir faire en sorte que le programme en modifie les intituls. C'est cette mthode que nous allons choisir, car elle prsente plusieurs avantages : - Elle est plus conforme aux conventions habituelles des interfaces graphiques, puisque le changement d'intitul d'un bouton sur lequel on vient de cliquer est un phnomne assez banal, alors que l'action consistant cliquer sur une zone de texte est normalement destine y faire apparatre la barre verticale clignotante associe l'dition de texte2. - Cette "orthodoxie" du changement d'intitul d'un bouton a deux consquences positives : d'une part les utilisateurs comprendront plus facilement ce qu'ils sont censs faire, et, d'autre part, l'diteur de dialogue et la librairie graphique vont nous faciliter la tche (alors que l'appel d'une fonction en cas de clic sur une zone de texte doit tre mis en place de faon "artisanale", ce qui est un peu plus dlicat). - La technique permettant de changer l'intitul d'un bouton permet galement d'en modifier d'autres caractristiques, ce qui va nous permettre de rendre certains boutons temporairement inactifs (pour empcher un joueur de placer sa marque dans une case dj occupe par son adversaire, par exemple). Le choix de boutons pour figurer les cases du jeu a une consquence majeure sur l'architecture de notre programme : le clic sur chacune de ces cases va dclencher l'excution d'une fonction diffrente (celle associe au bouton concern).

Ce qu'on appelle "donner le focus" la zone de texte. J-L Pris - 12/01/04

VC++ 6.0 - Qt 2.3 Alternance des marques

TD 5 : tic tac toe

3/10

Lorsque nous allons modifier l'intitul d'un bouton, un problme va se poser : quel est le nouvel intitul qui doit apparatre ? La faon la plus simple de rsoudre ce problme est sans doute de crer une variable membre de la classe du dialogue qui permettra d'identifier le joueur dont c'est le tour de jouer. Chacune des fonctions associes aux boutons aura accs cette variable (puisque ces fonctions sont galement membres de la classe du dialogue) et s'en servira pour dterminer la marque qui doit apparatre. Chacune de ces fonctions prendra videmment soin de modifier ensuite la variable en question, pour que le coup suivant corresponde l'autre joueur. Remise du jeu dans son tat initial Cette opration ne prsente gure de difficult : chacun des 9 boutons doit retrouver un intitul vierge et tre rendu disponible pour qu'un joueur puisse y placer sa marque. Dtection de la victoire ventuelle d'un des joueurs De nombreuses approches sont envisageables pour aborder ce problme, et en examiner plusieurs pour faire ressortir leurs avantages et inconvnients respectifs dpasserait notre propos actuel (qui n'est, rappelons-le, que de raliser un petit programme illustrant l'usage de paramtres...). Nous allons donc opter pour une mthode qui prsente l'avantage de ne pas tre trop difficile expliquer et de ne ncessiter la mise en uvre d'aucune technique que nous n'ayons dj utilise.
Cette mthode prsente, en revanche, l'inconvnient de conduire une certaine profusion de variables membre, un dfaut qui doit normalement tre vit. L'intrt des techniques de structuration des donnes qui permettent de pallier cet inconvnient ne vous en paratra que plus manifeste lorsque nous les introduirons !

Remarquons tout d'abord qu'il n'existe que huit alignements permettant de gagner ce jeu : trois lignes, trois colonnes et deux diagonales. Il est donc envisageable de tenir jour l'tat de ralisation de chacun de ces huit alignements, en crant cet effet huit variables membre. Chacune des cases n'est pertinente que pour certains alignements. La case centrale de la ligne suprieure, par exemple, ne contribue la ralisation que de deux alignements : la ligne suprieure et la colonne centrale. La case centrale, par contre, contribue la ralisation de la colonne centrale, de la ligne centrale et des deux diagonales. Comme l'occupation de chacune des cases donne lieu l'appel d'une fonction spcifique, il est facile de faire en sorte que la fonction en question modifie l'tat de ralisation des alignements concerns, et seulement de ceux-ci. Si l'on envisage les choses du point de vue de l'un des alignements, il s'agit de tenir jour le nombre de marques places par chacun des joueurs. Lorsque l'un de ces nombres atteint trois, l'alignement est ralis et la partie est gagne pour le joueur correspondant. Comme une simple variable de type numrique ne peut contenir qu'une seule valeur et que nous devons en stocker deux, nous serons amens crer un type spcifique, destin reprsenter l'tat d'un alignement. Tous les dtails ne sont, certes, pas rgls, mais nous avons maintenant une reprsentation assez claire de comment nous allons nous y prendre et nous pouvons donc passer aux actes.

2 - Cration du projet et dessin de l'interface


En vous inspirant de la procdure dcrite dans le bas sur un TD 3, crez un projet nomm TD05 dialogue ressemblant celui reprsent page 2 .
Commencez par crer un bouton et donnez lui les caractristiques souhaites (size policy horizontale et verticale "prefered/prefered" et font de grande taille) avant de le dupliquer par copier/coller.

Les boutons figurant les cases doivent tre nomms d'une faon rappelant la ligne et la colonne occupe : b_L1C1, b_L1C2, b_L1C3, b_L2C1, b_L2C2, b_L2C3, b_L3C1, b_L3C2 et b_L3C3 . Le bouton d'effacement est baptis b_effacer .
Les connexions signal/slots du TD 5

Crez les slots et tablissez les connexions ncessaires . (cf. tableau ci-contre)

J-L Pris - 12/01/04

VC++ 6.0 - Qt 2.3

TD 5 : tic tac toe

4/10

3 - Ecriture du code
La fonction la plus facile crire est sans doute celle qui efface toutes les cases et remet le programme dans un tat qui permet aux utilisateurs de faire une nouvelle partie. Commencer par crire cette fonction va, par ailleurs, nous permettre de mettre en place les bases de notre gestion de l'alternance des marques et de la dtection de la fin d'une partie.

La fonction f_effacer() Cette fonction, qui sera appele lors du lancement du programme (pour prparer la premire partie) et entre chaque partie (lorsque l'utilisateur cliquera sur le bouton "Effacer") doit prendre quatre mesures : - Eliminer les marques ventuellement prsentes dans certaines cases. - Rendre toutes les cases accessibles au premier joueur. - Placer chacune des variables reprsentant une possibilit de victoire dans un tat signifiant qu'aucune des cases ne la concernant n'est actuellement occupe. - Choisir l'identit du joueur qui va commencer. Effacement des marques Plutt que de chercher dterminer quelles cases ont rellement besoin d'tre effaces, il est plus efficace d'ordonner chacun des boutons d'afficher une chane vide : //Cette fonction est appele en dbut de programme et //quand l'utilisateur clique sur le bouton [Effacer] void TD05Dialog::f_effacer() { //vider toutes les cases b_L1C1->setText(""); b_L1C2->setText(""); b_L1C3->setText(""); b_L2C1->setText(""); b_L2C2->setText(""); b_L2C3->setText(""); b_L3C1->setText(""); b_L3C2->setText(""); b_L3C3->setText(""); Rendre toutes les cases utilisables Ceci revient rendre disponibles les boutons reprsentant ces cases, et une fonction de la classe QButton est prvue pour cela :
12 13 14 15 16 17 18 19 20

1 2 3 4 5 6 7 8 9 10 11

//rendre tous les boutons disponibles b_L1C1->setEnabled(true); b_L1C2->setEnabled(true); b_L1C3->setEnabled(true); b_L2C1->setEnabled(true); b_L2C2->setEnabled(true); b_L2C3->setEnabled(true); b_L3C1->setEnabled(true); b_L3C2->setEnabled(true); b_L3C3->setEnabled(true);
Les fonctions setText() et setEnabled() utilisent des paramtres qui permettent de leur indiquer respectivement quel texte doit tre affich dans le bouton et si le bouton doit tre rendu actif ou inactif. Ce type de paramtres est tellement "intuitif" que nous avons commenc l'utiliser avant mme d'avoir tudi la Leon 5 (le TD 3 utilise la fonction display(), qui est au QMultiLineEdit ce que setText() est au QButton). Ces fonctions doivent, ici, tre excutes au titre de chacun des boutons concerns, ce qui exige que chacune d'entre-elles soit appele neuf fois (nous ne disposons pas encore des outils qui nous permettraient d'utiliser une boucle pour procder ces appels rpts, et nous devons donc nous contenter de recopier plusieurs fois des lignes de code quasi identiques.

J-L Pris - 12/01/04

VC++ 6.0 - Qt 2.3 Remettre zro les alignements

TD 5 : tic tac toe

5/10

Nous avons dcid que les huit alignements possibles allaient tre reprsents chacun par une instance d'une classe conue spcialement cet effet, que nous pouvons dcider de baptiser CAlignement. Nous sommes donc conduits dcider que cette classe devra offrir une fonction membre permettant de placer une instance dans l'tat correspondant l'absence de marques la concernant. Le nom de cette fonction pourrait tre reset(), un verbe souvent employ en informatique dans ce genre de contexte. La classe CAlignement devra disposer d'une fonction reset().
Lorsque nous nous chercherons dfinir la classe CAlignement, l'ensemble des exigences que nous aurons formules son sujet au cours de l'criture du reste du programme nous servira de guide pour dcider de son fonctionnement interne.
21 22 23 24 25 26 27 28

//remettre zro tous les alignements diagonaleUn.reset(); diagonaleDeux.reset(); ligneDuHaut.reset(); ligneDuMilieu.reset(); ligneDuBas.reset(); colonneDeGauche.reset(); colonneDuMilieu.reset(); colonneDeDroite.reset(); La classe TD05Dialog devra comporter huit variables membre de type CAlignement Dsignation du joueur qui va commencer Comme dans le cas de la mmorisation de l'opration choisie lors de l'utilisation de la calculette (TD 3), le recours une variable d'un type numr semble ici s'imposer. Si le dialogue possde une variable membre de ce type nomme joueurActif, indiquer que c'est au premier joueur de placer sa marque revient simplement donner la bonne valeur cette variable :

29 30

//indiquer que c'est au premier joueur de mettre une marque joueurActif = JOUEUR_UN; } //fin de la fonction f_effacer() Il faudra crer un type EJoueur admettant les valeurs JOUEUR_UN et JOUEUR_DEUX. Il faudra ajouter la classe TD05Dialog un membre de type EJoueur nomm joueurActif. Crez la fonction f_effacer() (clic droit sur la classe TD05Dialog dans l'onglet ClassView de la fentre Workspace, puis choix de l'option "Add member function"). Insrez dans le corps de cette fonction le code que nous venons de dcrire . Insrez galement, au dbut du fichier TD05Dialog.cpp, les directives qui permettent au compilateur de savoir ce qu'est un QButton et une QMessageBox3 , ainsi que l'appel de la fonction f_effacer() qui doit tre excut en dbut de programme :

1 2 3 4 5 6 7 8 9

#include "td05dialog.h" #include "QPushButton.h" #include "QMessageBox.h"


TD05Dialog::TD05Dialog( QWidget* parent, const char* name, bool modal, WFlags f )

: TD05DialogBase( parent, name, modal, f ) { // Add your code f_effacer(); }

La classe QMessageBox sera utilise pour afficher le message signalant la victoire de l'un des joueurs. J-L Pris - 12/01/04

VC++ 6.0 - Qt 2.3

TD 5 : tic tac toe

6/10

Premire bauche d'une fonction associe un bouton "case" Les fonctions associes aux boutons reprsentant les cases du jeu constituent le cur du programme. La tche de ces fonctions comporte trois aspects : la matrialisation du coup exprim par le clic sur le bouton, la mise jour des variables reprsentant les alignements et, en cas de victoire de l'un des joueurs, l'arrt de la partie et l'affichage d'un message. Essayons, dans un premier temps, d'imaginer quoi pourrait ressembler la fonction associe au bouton situ sur la premire ligne, dans la premire colonne. Matrialisation du coup Trois oprations sont ncessaires pour matrialiser l'occupation de la case sur laquelle un joueur vient de cliquer. Il faut en effet : - dsactiver le bouton concern (pour qu'aucun joueur ne soit en mesure de l'utiliser nouveau durant la partie en cours) - faire apparatre la marque correspondant l'utilisateur qui vient de cliquer sur le bouton - indiquer que le prochain coup sera le fait de l'autre joueur. Ces deux dernires oprations se traduisent par des actions dpendant de lidentit du joueurActif. Elles donnent donc lieu une excution conditionnelle contrle par cette identit :
1 2 3 4 5 6 7 8 9 10 11 12 13

void TD05Dialog::f_L1C1() { b_L1C1->setEnabled(false); //dsactivation de la case qui vient dtre choisie if(joueurActif == JOUEUR_UN) { b_L1C1->setText("X"); //affichage de la marque du JOUEUR_UN joueurActif = JOUEUR_DEUX; //changement de joueur (cas 1) } else { b_L1C1->setText("O"); //affichage de la marque du JOUEUR_DEUX joueurActif = JOUEUR_UN; //changement de joueur (cas 2) } Mise jour des alignements La mise a jour des alignements n'est pas, en elle-mme une opration trs complique : il suffit de "prvenir" chacun des alignements concerns par la case qui vient d'tre choisie du fait que le joueurActif vient d'y placer sa marque. Cette opration peut tre facilement effectue si l'on dote la classe CAlignement d'une fonction ajouteMarque(). Un facteur supplmentaire doit cependant tre pris en compte : chacun des alignements concerns risque de se voir rempli par la marque ajoute, ce qui indique que le joueurActif vient de gagner la partie. Plutt que de chercher dtecter cette situation en pratiquant un test aprs chaque mise jour d'un alignement, il est plus "conomique" de transmettre une mme variable chaque appel de ajouteMarque(), tant entendu que cette fonction ne modifiera le contenu de cette variable que si elle diagnostique la victoire du joueurActif.

14 15 16 17

bool partieGagnee = false; ligneDuHaut.ajouteMarque(joueurActif, & partieGagnee); colonneDeGauche.ajouteMarque(joueurActif, & partieGagnee); diagonaleUn.ajouteMarque(joueurActif, & partieGagnee);
La variable partieGagnee tant initialise avec la valeur fausse, il suffit que l'un des trois appels ajouteMarque() donne lieu au diagnostic de victoire pour que partieGagnee devienne vraie.

La classe CAlignement doit comporter une fonction membre nomme ajouteMarque() et comportant deux paramtres. Le premier est de type EJoueur et il indique quel joueur vient d'occuper une des cases de l'alignement. Le second est l'adresse d'un boolen que la fonction doit rendre vrai si l'ajout de la marque conduit le joueur la victoire.
Il aurait t possible de faire de ce second paramtre une rfrence un boolen plutt qu'un pointeur sur un boolen. On peut cependant prfrer rendre bien visible le fait que la fonction ajouteMarque() est susceptible de modifier la valeur de la variable partieGagnee.
J-L Pris - 12/01/04

VC++ 6.0 - Qt 2.3 En cas de victoire

TD 5 : tic tac toe

7/10

Il faut rendre indisponibles tous les boutons, de faon ce quil ne soit plus possible dajouter des marques. Pour viter tout risque de malentendu (au cas o les joueurs nauraient pas remarqu que lun dentre eux a gagn), cet arrt de la partie sera accompagn dun message explicatif.
18 19 20 21 22 23 24 25 26 27 28 29 30 31

if(partieGagnee) { b_L1C1->setEnabled(false); //on met fin la partie b_L1C2->setEnabled(false); //en dsactivant tous les boutons b_L1C3->setEnabled(false); b_L2C1->setEnabled(false); b_L2C2->setEnabled(false); b_L2C3->setEnabled(false); b_L3C1->setEnabled(false); b_L3C2->setEnabled(false); b_L3C3->setEnabled(false); QMessageBox::information(0, "Tic tac toe", "Bravo !"); } } //fin de la fonction f_L1C1()
Comme dans la fonction f_effacer(), il est ici prfrable de ne pas chercher viter les oprations inutiles. Dterminer si un bouton est ou non disponible ncessite un appel de fonction, et la logique conditionnelle qu'il faudrait mettre en place pour ne dsactiver que les boutons disponibles alourdirait le code source sans amliorer l'efficacit du programme. La fonction utilise (29) pour afficher un message (dans une fentre qui lui est propre et qui se superpose celle reprsentant le jeu) utilise trois paramtres. Nous reviendrons plus en dtails sur son utilisation lors dun prochain TD.

La fonction codeCommunATousLesCoups() Si lon examine notre premire bauche de fonction f_L1C1(), on remarque que seule la mise jour des alignements est spcifique ce bouton. Tout le reste de la fonction pourrait tre dplac dans une fonction laquelle il suffirait de transmettre le verdict des alignements et ladresse du bouton qui vient dtre cliqu pour quelle puisse effectuer tous les traitements ncessaires :
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

void TD05Dialog:: codeCommunATousLesCoups(bool victoire, QButton * leBouton) { //Matrialisation du coup leBouton->setEnabled(false); //dsactivation de la case qui vient dtre choisie if(joueurActif == JOUEUR_UN) { leBouton ->setText("X"); //affichage de la marque du JOUEUR_UN joueurActif = JOUEUR_DEUX; //changement de joueur (cas 1) } else { leBouton ->setText("O"); //affichage de la marque du JOUEUR_DEUX joueurActif = JOUEUR_UN; //changement de joueur (cas 2) } //en cas de victoire if(victoire) { b_L1C1->setEnabled(false); //on met fin la partie b_L1C2->setEnabled(false); //en dsactivant tous les boutons b_L1C3->setEnabled(false); b_L2C1->setEnabled(false); b_L2C2->setEnabled(false); b_L2C3->setEnabled(false); b_L3C1->setEnabled(false); b_L3C2->setEnabled(false); b_L3C3->setEnabled(false); QMessageBox::information(0, "Tic tac toe", "Bravo !"); } }
J-L Pris - 12/01/04

VC++ 6.0 - Qt 2.3

TD 5 : tic tac toe

8/10

Les fonctions associes aux boutons "case" Si la fonction la fonction codeCommunATousLesCoups() est disponible, la fonction f_L1C1() se trouve considrablement simplifie :
1 2 3 4 5 6 7 8

void TD05Dialog::f_L1C1() { bool partieGagnee = false; ligneDuHaut.ajouteMarque(joueurActif, & partieGagnee); colonneDeGauche.ajouteMarque(joueurActif, & partieGagnee); diagonaleUn.ajouteMarque(joueurActif, & partieGagnee); codeCommunATousLesCoups(partieGagnee, b_L1C1) ; } Crez les fonctions codeCommunATousLesCoups() dcrit ci-dessus . et f_L1C1() et donnez-leur le contenu

Crez les fonctions f_L1C2() f_L3C3() et placez dans chacune dentre-elles le code ncessaires au bon fonctionnement du jeu .
Ces huit fonctions ne se distinguent de f_L1C1() que par lensemble des alignements concerns et par ladresse du bouton devant tre mis jour.

Cration du type EJoueur Comme nous l'avons vu dans le TD02, il est prfrable de crer un fichier .h spcifique pour y dfinir le type dont nous avons besoin. Dans le menu "File" de Visual C++, choisissez la commande "New.." . et Dans l'onglet "Files" du dialogue qui s'ouvre alors, slectionnez l'option "C/C++ Header File" tapez "JOUEUR.H" dans la zone d'dition "File Name:" , puis cliquez sur le bouton [OK] . Dans le fichier vierge qui est alors cr, tapez la dfinition de notre type
1 2

#pragma once enum EJoueur {JOUEUR_UN, JOUEUR_DEUX, ERREUR};


Mme si vous n'avez pas prvu d'utiliser cette possibilit, il est prfrable que les instances d'un type numr soient en mesure d'adopter une valeur explicitement illgitime. La directive #pragma once qui figure sur la ligne 1 est une commande propre au compilateur Microsoft qui permet d'viter le problme de la redfinition des valeurs en cas de #inclusion multiple du fichier dfinissant un type numr.

La classe CAlignement Nous savons que les variables de type CAlignement doivent tre capables de tenir jour le nombre de marques que chaque joueur a plac dans les cases correspondantes. Ce dcompte peut tre ralis l'aide de deux variables membre de type int, que nous nommerons nbMarquesUn et nbMarquesDeux. De plus, l'criture du programme nous a conduit mettre deux exigences concernant la classe CAlignement : - La classe CAlignement devra disposer d'une fonction reset(). - La classe CAlignement doit comporter une fonction membre nomme ajouteMarque() et comportant deux paramtres. Le premier est de type EJoueur et il indique quel joueur vient d'occuper une des cases de l'alignement. Le second est l'adresse d'un boolen que la fonction doit rendre vrai si l'ajout de la marque conduit le joueur la victoire. Cration de la classe Dans l'onglet "ClassView" de le fentre "Workspace", cliquez avec le bouton droit sur la ligne TD05 Classes. Dans le menu qui apparat alors, choisissez la commande "New Class..." . Dans la zone d'dition "Name:" du dialogue de cration de classe, tapez CAlignement, puis cliquez sur le bouton [OK] .

J-L Pris - 12/01/04

VC++ 6.0 - Qt 2.3 Cration des membres

TD 5 : tic tac toe

9/10

Ajoutez la classe CAlignement les deux variables membres nbMarquesUn et nbMarquesDeux Ajoutez aussi la classe CAlignement les fonctions membre reset() et ajouteMarque() .

Etant donn que la fonction ajouteMarque() utilise un paramtre de type EJoueur, il faut ajouter une directive #include "joueur.h" dans le fichier CAlignement.h, avant le dbut de la . dfinition de la classe La fonction reset() Cette fonction se borne ramener les deux variables membre zro. Insrez donc dans son corps : les deux instructions ncessaires
1 2 3 4 5

void CAlignement::reset() { nbMarquesUn = 0; nbMarquesDeux = 0; } La fonction ajouteMarque() Le rle de cette fonction est d'ajouter un l'une ou l'autre des variables membre, en fonction de la valeur qui lui a t transmise pour initialiser son premier paramtre. Si l'une des deux variables membre atteint la valeur 3, c'est que l'alignement au titre duquel la fonction est excute vient d'tre ralis par leJoueur. Il faut donc que la fonction signale la fin de la partie en plaant la valeur vraie dans la variable boolenne dont l'adresse figure dans son second paramtre :

1 2 3 4 5 6 7 8 9

void CAlignement::ajouteMarque(EJoueur leJoueur, bool *victoire) { if(leJoueur == JOUEUR_UN) nbMarquesUn = nbMarquesUn + 1; else nbMarquesDeux = nbMarquesDeux + 1; //partie finie ? if(nbMarquesUn == 3 || nbMarquesDeux == 3) *victoire = true; } Insrez le code ci-dessus dans le corps de la fonction ajouteMarque() Les variables membre de la classe TD05Dialog Pour que le programme soit complet, il reste encore ajouter la classe TD05Dialog les huit variables membre de type CAlignement promises , ainsi que la variable membre joueurActif . Le contenu du fichier TD05Dialog.h doit finalement tre : .

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

#include "td05dialogbase.h" #include "JOUEUR.H" // Added by ClassView #include "Alignement.h" // Added by ClassView class TD05Dialog : public TD05DialogBase { Q_OBJECT public: TD05Dialog(QWidget* parent=0,const char* name=0,bool modal=FALSE,WFlags f=0); EJoueur joueurActif; CAlignement diagonaleUn; CAlignement diagonaleDeux; CAlignement ligneDuHaut; CAlignement ligneDuMilieu; CAlignement ligneDuBas; CAlignement colonneDeGauche; CAlignement colonneDuMilieu;
J-L Pris - 12/01/04

VC++ 6.0 - Qt 2.3


17 18 19 20 21 22 23 24 25 26 27 28 29

TD 5 : tic tac toe

10/10

CAlignement colonneDeDroite; void f_effacer(); void f_L1C1(); void f_L1C2(); void f_L1C3(); void f_L2C1(); void f_L2C2(); void f_L2C3(); void f_L3C1(); void f_L3C2(); void f_L3C3(); void codeCommunATousLesCoups(bool victoire, QButton * leBouton); };
Lorsque vous utilisez la commande "Add member variable" pour ajouter une classe une variable membre qui est une instance d'un type que vous avez prcdemment dfini, Visual C++ insre automatiquement dans le fichier .h qui contient la dfinition de la classe la directive #include ncessaire (ligne 2 et 3) pour que ce type soit reconnu lors de la compilation. Si vous utilisez une autre mthode pour ajouter de telles variables membre (en tapant directement leur dclaration dans le fichier .h, par exemple), il vous faut en revanche veiller vous-mme la #inclusion des fichiers .h dfinissant les types concerns.

Vous pouvez maintenant compiler

et excuter

votre programme.

4 - Questions et exercices
1) Pourquoi la fonction ajouteMarque() doit-elle utiliser un paramtre de type EJoueur, alors que la fonction codeCommunATousLesCoups(), par exemple, s'en passe parfaitement ? 2) Si la fonction suivante est dfinie :
1 2 3 4 5

void TD05Dialog::resetLaCase(QButton *laCase) { laCase->setText(""); laCase-> setEnabled(true); } comment pouvez-vous rcrire la fonction f_effacer() ? 3) Un programmeur a tent de dfinir ainsi la fonction ajouteMarque() :

1 2 3 4 5 6 7

void CAlignement::ajouteMarque(EJoueur leJoueur, bool *victoire) { int *aModifier = (leJoueur == JOUEUR_UN)? &m_scoreJoueurDeux : &m_scoreJoueurUn; aModifier = aModifier + 1; if (aModifier == 3) *victoire = true; } Quelles erreurs a-t-il commises ?

J-L Pris - 12/01/04

Вам также может понравиться