Vous êtes sur la page 1sur 10

Centre Informatique pour les Lettres

et les Sciences Humaines


TD 8 : La patience des pharaons





1 - Analyse pralable ............................................................................................................... 2
2 - Cration du projet et dessin de l'interface ........................................................................... 3
3 - La classe de dialogue.......................................................................................................... 4
Le constructeur .............................................................................................................. 4
Cration du jeu de carte......................................................................................... 4
Positionnement des boutons et distribution des cartes........................................... 5
La fonction t i r er UneCar t eDans( ) ................................................................................. 6
La fonction cal cul eGeomet r i e( ) ................................................................................... 6
La fonction descendr e( ) ................................................................................................ 7
La fonction pi ocher ( ) .................................................................................................... 8
4 - La classe CCar t e................................................................................................................ 9
Dfinition de la classe..................................................................................................... 9
La fonction devi ent ( ) .................................................................................................... 9
La fonction associ eBout on( ) ........................................................................................ 9
La fonction val eur ( ) ....................................................................................................10
La fonction r ecoi t ( ) ....................................................................................................10
La fonction mont r eToi ( ) ...............................................................................................10
5 - Exercice.............................................................................................................................10


Document du 22/08/05 - Retrouvez la version la plus rcente sur http://www.up.univ-mrs.fr/wcpp
VC++ 6.0 - Qt 3.2 TD 8 : La patience des pharaons 2/10
Le programme ralis au cours de ce TD est
une version informatise du jeu de cartes
connu sous le nom de "russite des pharaons".

Le but de ce jeu est de faire disparatre toutes
les cartes initialement arranges sur le plateau
dans une disposition voquant trois
pyramides. Une carte peut descendre sur le
tas plac sous les pyramides si et seulement si
sa valeur est immdiatement suprieure ou
infrieure celle de la carte place au sommet
de ce tas. (Les as sont considrs la fois
comme suprieurs aux rois et comme
infrieurs aux deux.)


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

Dans la configuration reprsente ci-dessus, le deux (de cur) figurant au sommet du tas
autorise la descente soit de l'as (de pique), soit du trois (de cur). Ce second mouvement est
prfrable, puisqu'il permet la descente ultrieure du quatre (de trfle), puis du cinq (de cur),
puis du quatre (de pique) et enfin du cinq (de trfle). Remarquez que, dans ce jeu, seule la valeur
des cartes est prise en compte, leur couleur (pique, cur, carreau ou trfle) est sans importance.

Au dbut du jeu, seules les cartes de la range infrieure des pyramides sont accessibles. Une
carte initialement "bloque" n'est libre que lorsque les cartes qui en occultent la partie basse
sont toutes deux descendues sur le tas. Si aucun mouvement de descente n'est possible, le joueur
doit placer sur le tas la carte occupant le sommet de la pioche. Si cette pioche est puise et qu'il
reste des cartes dans les pyramides, la partie est perdue.
1 - Analyse pralable
Les rgles du jeu exigent que notre programme soit en mesure de manipuler deux ensembles de
cartes : celles qui figurent dans les pyramides et celles qui sont disponibles dans la pioche.

L'accs aux cartes places dans les pyramides doit pouvoir se faire au gre des choix faits par le
joueur parmi les possibilits que lui laisse la distribution des cartes. Il semble donc naturel
d'organiser ces cartes dans une QMap, puisque ce type de conteneur permet d'accder facilement
n'importe lequel des lments qu'il contient.

L'accs aux cartes places dans la pioche va, en revanche, se faire dans un ordre parfaitement
prvisible : seule la premire d'entre-elles est accessible, et un conteneur de type QVal ueLi st
convient donc parfaitement.

Une autre carte joue un rle important : celle qui figure au sommet du tas, dont la valeur
conditionne les mouvements possibles. Les autres cartes du tas ne sont plus en jeu, et il n'est pas
ncessaire d'en conserver une reprsentation. Le tas ne sera donc pas gr l'aide d'une
collection, mais d'une simple instance de la classe que nous allons crer spcialement pour
reprsenter les cartes, la classe CCar t e.

Les pyramides, la pioche et le sommet du tas constituent les donnes essentielles de la
reprsentation de l'tat de la partie et l'option la plus raisonnable est certainement d'en faire trois
variables membre de la classe reprsentant notre dialogue.

Pour viter de toujours proposer la mme disposition initiale des cartes (ce qui priverait vite le jeu
de tout intrt), notre programme fera appel aux techniques d'utilisation de nombres pseudo-
alatoires dcrites dans l'Annexe 2.

En ce qui concerne la reprsentation des cartes, nous allons nous appuyer sur des widgets
familiers : des QPushBut t on, qui se prtent facilement aussi bien l'affichage d'images qu'au
dclenchement de l'excution d'une fonction lorsque l'utilisateur clique dessus. En raison du
nombre d'objets concerns, nous allons utiliser un widget de type but t onGr oup pour regrouper
les 28 boutons reprsentant les pyramides.

Grce ce but t onGr oup, nous allons pouvoir d'une part ajuster prcisment la position des
cartes l'aide de quelques ligne de code figurant dans le constructeur de la classe de dialogue et,
d'autre part, utiliser un slot unique (qui dispose d'un paramtre lui permettant de recevoir une
valeur indiquant lequel des boutons du groupe a t cliqu), ce qui nous pargnera la cration de
28 fonctions quasiment identiques.
J-L Pris - 22/08/05
VC++ 6.0 - Qt 3.2 TD 8 : La patience des pharaons 3/10
2 - Cration du projet et dessin de l'interface
En vous inspirant de la procdure dcrite dans le TD 3, crez un projet nomm TD08 .

Eliminez tous les widgets du dialogue, et remplacez les par un bouton nomm car t e .

Slectionnez ce bouton , copiez-le et collez-le 27 fois .

Le raccourci clavier correspondant l'action "Coller" est [Ctrl V]. Les copies successives
s'empilent les unes sur les autres, de sorte qu'elles n'ont pas d'effet visible. En revanche,
Qt Designer numrote judicieusement les boutons ainsi crs : car t e_2, car t e_3, etc. Il vous
est donc facile de continuer faire des copies jusqu' ce que le bouton car t e_28 apparaisse
Ne vous proccupez pas de la disposition de ces cartes, il faut simplement qu'il y en ait 28.

Crez un buttonGroup (menu "Tools", catgorie "Containers") englobant la "pile" de 28 boutons .

Ouvrez, si ncessaire, la fentre Object Explorer (menu Window,
catgorie Views) et vrifiez que les 28 cartes sont bien DANS le
gr oupePyr ami des (cf ci-contre) .

Rebaptisez ce buttonGroup gr oupePyr ami des et donnez ses
proprits geometry/width et geometry/height les valeurs 733 et
273 .

Eliminez le texte correspondant la proprit "title" du
gr oupePyr ami des .

Ajustez la taille du dialogue de faon ce que le
gr oupePyr ami des y tienne et qu'il reste un peu de place en bas
pour la pioche et le tas .


Si vous le souhaitez, vous pouvez aussi modifier la proprit PaletteBackgroundColor du
dialogue, de faon ce que les pyramides soient visuellement plus saillantes.

Crez un slot nomm descendr e( i nt ) et associez-lui l'vnement cl i cked( i nt ) du
gr oupePyr ami des .

La fonction correspondant ce slot ne sera pas excute lorsque l'utilisateur cliquera sur le
buttonGroup, mais lorsqu'il cliquera sur l'un des boutons qui figurent dans ce groupe.

Placez deux boutons nomms b_pi oche et b_t as dans la partie infrieure du dialogue, et donnez
leurs proprits geometry/width et geometry/height les valeurs 75 et 102 .

Crez un slot nomm pi ocher ( ) et
associez-le l'vnement cl i cked( ) du
bouton b_pi oche .

Ajoutez finalement un QLCDNumber
(menu "Tools", catgorie "Display")
nomm LCDr est e , qui servira
indiquer au joueur combien de cartes
sont encore disponibles dans la pioche.

Votre dialogue devrait maintenant
ressembler celui reprsent ci-contre.

Enregistrez votre travail (Menu "File", commande "Save") , puis revenez Visual C++ et
procdez aux modifications de rigueur sur la fonction mai n( ) , de faon ce qu'elle instancie la
classe TD08Di al ogI mpl .
J-L Pris - 22/08/05
VC++ 6.0 - Qt 3.2 TD 8 : La patience des pharaons 4/10
3 - La classe de dialogue
La premire chose faire est de crer les trois variables membre dont notre analyse pralable a
fait apparatre la ncessit. Dans l'onglet "File View" de la fentre "Workspace", ouvrez l'onglet
"Header Files" et double-cliquez sur l'entre "td08dialogimpl.h" .

Compltez la dfinition de la classe (10-12), sans oublier (2-4) les inclusions ncessaires .

#i ncl ude " t d08di al og. h" 1
#i ncl ude " qmap. h" 2
#i ncl ude " qval uel i st . h" 3
#i ncl ude " car t e. h" 4
cl ass TD08Di al ogI mpl : publ i c TD08Di al og 5
{ 6
Q_OBJ ECT 7
publ i c: 8
TD08Di al ogI mpl ( QWi dget * par ent =0, const char * name=0, bool modal =FALSE, WFl ags f =0 ) ; 9
/ / var i abl es membr e
QMap <i nt , CCar t e> pyr ami des; 10
QVal ueLi st <CCar t e> pi oche; 11
CCar t e sommet Tas; 12
}; 13

La variable pyr ami des est de type QMap <i nt , CCar t e>, ce qui signifie qu'il s'agit d'une
collection dans laquelle une valeur entire nous permettra d'accder la carte correspondante.
Cette association i nt / CCar t e mrite peut-tre quelques explications complmentaires.

Que viennent faire des i nt dans cette histoire ?
Nous avons vu que la fonction descendr e( ) , qui correspond au signal mis lorsque l'utilisateur
clique sur l'une des cartes des pyramides, dispose d'un paramtre de type i nt . Cette fonction va
recevoir une valeur entire, qui est la "signature" du bouton ayant dclench son excution.
Reprsenter les pyramides l'aide d'une QMap dont les cls sont des i nt permet donc la
fonction descendr e( ) d'utiliser directement cette signature pour accder la carte concerne.

Des CCar t e ? Qusaco ?
Pour l'instant, nous n'en savons rien. A mesure que nous avancerons dans la mise au point du
programme, les fonctionnalits dont la classe CCar t e devra disposer apparatront
progressivement. La dfinition de cette classe sera donc la dernire tape de notre projet.
Le constructeur
Plusieurs lments de la situation initiale de jeu manquent encore, et leur mise en place incombe
assez naturellement au constructeur de notre classe de dialogue. Celui-ci va notamment
devoir positionner les boutons reprsentant les pyramides et distribuer les cartes. Pour pratiquer
cette distribution, nous allons crer une collection contenant toutes les cartes, ce qui nous
permettra de procder un tirage au hasard (sans remise) parmi les lments de cette collection.
Cration du jeu de carte
La fonction qui permet d'obtenir un "tirage au hasard" produit des valeurs entires (cf. Annexe 2).
L'utilisation de ces valeurs pour extraire des lments d'une collection sera d'une grande
simplicit si la collection en question est une QMap dont les cls sont des entiers. La cration du
jeu relve donc d'une simple boucle ajoutant 52 cartes la collection, chaque carte se
singularisant d'une part par leur valeur (de 0 pour un as 12 pour un roi, cette valeur tant
obtenue en calculant le reste de la division par 13 du numro de la carte) et, d'autre part, par
l'image qu'elle utilise pour se dessiner l'cran. Ces images sont contenues dans un rpertoire
baptis "cartes", sous la forme de fichiers nomms "0.png" (l'as de pique), "1.png" (le deux de
pique), , "51.png" (le roi de trfle). Remarquez (16) l'utilisation de la fonction ar g( ) pour
gnrer les noms de fichiers partir de la chane initiale (11).

#i ncl ude " t d08di al ogi mpl . h" 1
#i ncl ude " t i me. h" 2
#i ncl ude " qbut t ongr oup. h" 3
#i ncl ude " qmessagebox. h" 4
#i ncl ude " ql cdnumber . h" 5
#i ncl ude " qpushbut t on. h" 6
J-L Pris - 22/08/05
VC++ 6.0 - Qt 3.2 TD 8 : La patience des pharaons 5/10
TD08Di al ogI mpl : : TD08Di al ogI mpl ( QWi dget * par ent , const char * name, bool modal , 7
WFl ags f ) : TD08Di al og( par ent , name, modal , f )
{ 8
sr and( t i me( 0) ) ; / / i ni t i al i sat i on du gnr at eur de nombr e pseudo- al at oi r es 9
/ / cr at i on du j eu de car t es : une QMap pour t i r er f aci l ement une car t e au hasar d
QMap <i nt , CCar t e> l eJ eu; 10
QSt r i ng f i chi er = " car t es/ %1. png" ; 11
CCar t e aAj out er ; 12
i nt n = 0; 13
f or ( n=0; n < 52 ; ++n) 14
{ 15
aAj out er . devi ent ( n %13, f i chi er . ar g( n) ) ; 16
1
l eJ eu[ n] = aAj out er ; 17
} 18
Nous devons prendre note au passage d'une premire caractristique de la classe CCar t e :

1 : La classe CCar t e doit disposer d'une fonction membre nomme devi ent ( ) acceptant un
argument de type i nt et un argument de type QSt r i ng. Cette fonction fait adopter l'instance au
titre de laquelle elle est appele la valeur et le fichier image spcifis par ses paramtres.

Vous pouvez trouver ici un dossier compress contenant des images au format .png pouvant tre
utilises pour reprsenter les cartes. La ligne 4 suppose que ce dossier t dcompress et
plac dans celui qui contient le projet TD08. La cohrence entre valeurs des cartes et images
affiches repose, bien entendu, sur le respect d'une convention de dnomination des fichiers :
0.png, 13.png, 23.png et 39.png doivent reprsenter les as, 1.png, 14.png, 24.png et 40.png les
deux, et ainsi de suite.
Positionnement des boutons et distribution des cartes
La distribution des cartes se fait en deux temps : 28 cartes sont tout d'abord choisies et places
dans les pyramides (21), et les autres cartes sont ensuite places dans la pioche (26-27).

f or ( n=0 ; n < 28 ; ++n) 19
{/ / on choi si t 28 car t es pour gar ni r l es pyr ami des 20
pyr ami des[ n] = t i r er UneCar t eDans( l eJ eu) ; 21
QBut t on * unBout on = gr oupePyr ami des- >f i nd( n) ; 22
unBout on- >set Geomet r y( cal cul eGeomet r i e( n) ) ; 23
pyr ami des[ n] . associ eBout on( unBout on, n > 17) ; / / on voi t l es car t es 18 27 24
2
} 25
whi l e( ! l eJ eu. i sEmpt y( ) ) / / on met l e r est e dans l a pi oche 26
pi oche. append( t i r er UneCar t eDans( l eJ eu) ) ; 27

En plus de son transfert dans la QMap, le placement d'une carte dans les pyramides s'accompagne
de la mise en place du bouton correspondant. L'adresse de ce bouton est obtenue (22) l'aide
d'une fonction membre de la classe QBut t onGr oup, et il faut lui donner la taille requise et le
positionner au bon endroit sur le dialogue. Cette opration est effectue (23) en appelant la
fonction set Geomet r y( ) , mais quelques calculs sont ncessaires pour garantir un arrangement
correct des boutons. Ces calculs sont confis une fonction cal cul eGeomet r i e( ) , qu'il nous
faudra dfinir de faon ce que les boutons soient disposs ainsi :


Lorsqu'une des cartes des pyramides descendra sur le tas, il sera ncessaire de modifier
l'apparence du bouton correspondant, et le plus simple est sans doute de confier l'adresse de ce
bouton la carte concerne. Cette association est ralise (28) par la fonction associ eBout on( ) ,
qui reoit aussi un second paramtre indiquant si la carte doit tre rendue visible.
J-L Pris - 22/08/05
VC++ 6.0 - Qt 3.2 TD 8 : La patience des pharaons 6/10
Deux oprations sont encore ncessaires pour que la partie puisse commencer : le lien doit tre
tabli entre le sommet DuTas et le QPushBut t on qui sert le rendre visible (22) et une premire
carte doit tre tire de la pioche et place au sommet du tas (29).

/ / dbut de l a par t i e
sommet Tas. associ eBout on( b_t as, t r ue) ; 28
pi ocher ( ) ; 29
} 30

Donnez au corps de la fonction TD08Di al ogI mpl ( ) le contenu que nous venons de dcrire

et
remarquez que la ligne 24 introduit une deuxime contrainte pour la classe CCar t e:

2 : La classe CCar t e doit comporter une fonction membre nomme associ eBout on( ) acceptant
deux paramtres. Le premier est l'adresse d'un QPushBut t on que la fonction doit stocker dans
l'instance au titre de laquelle elle est invoque. Le second paramtre est un boolen qui indique si
la carte doit tre rendue visible.
La fonction t i r er UneCar t eDans( )
Cette fonction dispose d'un paramtre qui est une rfrence une collection de cartes, et son rle
est de choisir l'une des cartes, de la supprimer de la collection et d'en renvoyer la valeur.

On ne peut se contenter d'un paramtre de type QMap<i nt , CCar t e>, qui conduirait la fonction
disposer de son propre jeu de cartes. Retirer la carte choisie de ce jeu local resterait sans effet
sur le jeu cr par la fonction appelante, et nous n'aurions donc pas un tirage sans remise.

Pour tirer une carte dans la collection, nous devons choisir un nombre compris entre 0 et le
nombre de cartes prsentes dans cette collection.

S'il y a 52 cartes, elles ont pour cls 0, 1, 2,, 51. L'intervalle de choix inclut donc sa borne
infrieure (zro), mais exclut sa borne suprieure (le nombre de cartes disponibles).

Nous savons que la fonction r and( ) renvoie un i nt dont la valeur est imprvisible. Pour ramener
cette valeur dans notre intervalle de choix (3), nous pouvons nouveau utiliser l'oprateur %
(rappel : le reste de la division entire est strictement infrieur au diviseur).

CCar t e TD08Di al ogI mpl : : t i r er UneCar t eDans ( QMap <i nt , CCar t e> & j eu) 1
{ 2
i nt choi x = r and( ) %j eu. count ( ) ; / / un nombr e de l ' i nt er val l e [ 0, j eu. count ( ) [ 3
CCar t e t i r ee = j eu[ choi x] ; 4
j eu[ choi x] = j eu[ j eu. count ( ) - 1] ; 5
j eu. r emove( j eu. count ( ) - 1) ; 6
r et ur n t i r ee; 7
} 8

Une fois ce choix effectu, la carte tire peut tre mise de ct (4) et sa valeur limine du jeu.
Plutt que de retirer la valeur figurant la position tire (ce qui laisserait un "trou" dans le jeu,
c'est dire une cl infrieure au nombre de cartes et pour laquelle il n'existerait plus aucune
valeur), il est prfrable de remplacer la valeur de la carte choisie par celle de la dernire carte du
jeu (5) et de supprimer ensuite celle-ci (6).

Ajoutez la dclaration de la fonction t i r er UneCar t eDans( ) dans la dfinition de la classe
TD08Di al ogI mpl

et ajoutez la dfinition de cette fonction dans le fichier td08dialogimpl.cpp .
La fonction cal cul eGeomet r i e( )
Bien qu'indispensable au fonctionnement de notre programme, cette fonction est sans grand
intrt pdagogique : elle ne fait que dterminer la position d'un bouton tant donn son numro.
Un programmeur allergique l'arithmtique aurait pu en faire un swi t ch 28 case adoptant des
valeurs choisies empiriquement, et la version qui suit n'est peut tre pas beaucoup plus
intressante (un fichier texte est disponible ici pour copier/coller) :

QRect TD08Di al ogI mpl : : cal cul eGeomet r i e( const i nt qui ) 1
{ 2
const i nt LARGEUR_CARTE = 75; 3
const i nt HAUTEUR_CARTE = 102; 4
const i nt DELTA_V = 56; 5
const i nt DELTA_H = LARGEUR_CARTE - 2; 6
J-L Pris - 22/08/05
VC++ 6.0 - Qt 3.2 TD 8 : La patience des pharaons 7/10
QRect r eponse; 7
i f ( qui < 3) 8
{ 9
r eponse. set X( gr oupePyr ami des- >x( ) + ( 3 * qui + 1. 5) * DELTA_H) ; 10
r eponse. set Y( gr oupePyr ami des- >y( ) ) ; 11
} 12
i f ( qui >= 3 && qui < 9) 13
{ 14
r eponse. set X( gr oupePyr ami des- >x( ) + ( qui - 2 + ( qui >4) + ( qui >6) ) * DELTA_H) ; 15
r eponse. set Y( gr oupePyr ami des- >y( ) + DELTA_V) ; 16
} 17
i f ( qui >= 9 && qui < 18) 18
{ 19
r eponse. set X( gr oupePyr ami des- >x( ) + ( 0. 5 + ( qui - 9) ) * DELTA_H) ; 20
r eponse. set Y( gr oupePyr ami des- >y( ) + 2 * DELTA_V) ; 21
} 22
i f ( qui >= 18) 23
{ 24
r eponse. set X( gr oupePyr ami des- >x( ) + ( qui - 18) * DELTA_H) ; 25
r eponse. set Y( gr oupePyr ami des- >y( ) + 3 * DELTA_V) ; 26
} 27
r eponse. set Wi dt h( LARGEUR_CARTE) ; 28
r eponse. set Hei ght ( HAUTEUR_CARTE) ; 29
r et ur n r eponse; 30
} 31

Ajoutez la fonction cal cul eGeomet r i e( ) votre classe de dialogue .
La fonction descendr e( )
Lorsque le joueur clique sur l'une des cartes qui figurent dans les pyramides, cette carte doit
descendre sur le tas ( condition, toutefois, que les rgles du jeu autorisent ce mouvement). Le
dbut de la fonction descendre n'est donc pas trs difficile crire :

voi d TD08Di al ogI mpl : : descendr e( i nt qui ) 1
{ 2
/ / vr i f i e l a l gal i t du coup
i nt di f f er ence = abs( pyr ami des[ qui ] . val eur ( ) - sommet Tas. val eur ( ) ) ; 3
3
i f ( di f f er ence ! = 1 && di f f er ence ! = 12) 4
r et ur n; / / l es val eur s ne sont ni conscut i ves ni 0 et 12 : mouvement i l l gal 5

La fonction abs( ) renvoie la valeur absolue de son argument. Elle permet donc (3) de calculer
l'cart de valeur entre les deux cartes concernes, sans avoir s'occuper de qui est la plus petite.
Un cart de 12 signifie que l'une des deux cartes est un roi (valeur 12) et l'autre un as (valeur 0),
ce qui correspond un mouvement autoris.

3 : La classe CCar t e doit comporter une fonction membre nomme val eur ( ) renvoyant la valeur
de l'instance au titre de laquelle elle est invoque.

Si le mouvement est lgal, il faut l'effectuer. Le transfert de la carte dsigne sur le sommet du tas
(6) implique diverses manipulations sur les variables membre de la classe CCar t e, et comme
nous ignorons pour l'instant le dtail de l'organisation interne de celle-ci, il est prfrable de
confier cette tche une de ses fonctions membre :

4 : La classe CCar t e doit comporter une fonction membre nomme r ecoi t ( ) ayant pour effet de
transfrer la valeur et l'image de l'instance qui lui est passe comme argument dans l'instance au
titre de laquelle elle est invoque. L'image doit apparatre dans le bouton associ la carte
rceptrice, et le bouton associ l'autre carte doit disparatre.

/ / ef f ect ue l a descent e
sommet Tas. r ecoi t ( pyr ami des[ qui ] ) ; 6
pyr ami des. r emove( qui ) ; 7
4
i f ( pyr ami des. count ( ) == 0) / / par t i e f i ni e ? 8
QMessageBox: : i nf or mat i on( t hi s, " Phar aon" , " Br avo, vous avez gagn ! " ) ; 9

J-L Pris - 22/08/05
VC++ 6.0 - Qt 3.2 TD 8 : La patience des pharaons 8/10
Il faut ensuite mettre jour l'affichage, car il est possible que certaines cartes aient t libres
par la disparition de la carte descendue. Diffrentes mthodes sont envisageables, mais toutes
sont compliques par les irrgularits de la disposition des cartes. La mthode dcrite ci-dessous
ne tient pas compte de la position initiale de la carte qui vient d'tre descendue, mais examine
toutes les cartes pour vrifier que celles qui ne sont pas bloques sont bien affiches.

Pour les neuf premires cartes, la solution la plus claire me semble tre celle qui s'appuie sur une
numration explicite des obstacles qui les bloquent :

/ / r et our ne l es car t es vent uel l ement l i br es
QMap <i nt , i nt > bl ocage; 10
bl ocage[ 0] = 3; / / l a car t e 0 est bl oque par l a 3 et l a 4 11
bl ocage[ 1] = 5; / / l a car t e 1 est bl oque par l a 5 et l a 6 12
bl ocage[ 2] = 7; / / l a car t e 2 est bl oque par l a 7 et l a 8 13
bl ocage[ 3] = 9; / / l a car t e 3 est bl oque par l a 9 et l a 10 14
bl ocage[ 4] = 10; / / l a car t e 4 est bl oque par l a 10 et l a 11 15
bl ocage[ 5] = 12; / / l a car t e 5 est bl oque par l a 12 et l a 13 16
bl ocage[ 6] = 13; / / l a car t e 6 est bl oque par l a 13 et l a 14 17
bl ocage[ 7] = 15; / / l a car t e 7 est bl oque par l a 15 et l a 16 18
bl ocage[ 8] = 16; / / l a car t e 8 est bl oque par l a 16 et l a 17 19

Il suffit ensuite d'indiquer que si une carte est prsente dans les pyramides et que les deux
obstacles qui la concernent ont t retirs, alors cette carte doit apparatre :

i nt n; 20
f or ( n=0 ; n < 9 ; ++n) 21
i f ( pyr ami des. cont ai ns( n) ) 22
i f ( ! pyr ami des. cont ai ns( bl ocage[ n] ) && ! pyr ami des. cont ai ns( bl ocage[ n] +1) ) 23
pyr ami des[ n] . mont r eToi ( ) ; 24

5 : La classe CCar t e doit comporter une fonction mont r eToi ( ) capabl e de faire apparatre l'image
attribue la carte au titre de laquelle elle est appele dans le bouton associ cette carte.
5

Pour les cartes 9 17, le problme est bien plus simple, puisqu'on on obtient les numros des
cartes bloquantes en ajoutant respectivement 9 et 10 au numro de la carte considre :

f or ( n=9 ; n < 18 ; ++n) / / pour n>9, l a car t e n est bl oque par l a n+9 et l a n+10 25
i f ( pyr ami des. cont ai ns( n) ) 26
i f ( ! pyr ami des. cont ai ns( n+9) && ! pyr ami des. cont ai ns( n+10) ) 27
pyr ami des[ n] . mont r eToi ( ) ; 28
} 29

Ajoutez la fonction descendr e( ) votre classe de dialogue .
La fonction pi ocher ( )
Le rle principal de cette fonction est de transfrer (3-4) la premire carte de la pioche au sommet
du tas. Cette fonction s'occupe aussi d'afficher (6) le nombre de cartes encore disponibles dans la
pioche et de masquer le bouton correspondant lorsque celle-ci est puise (7-8) :

voi d TD08Di al ogI mpl : : pi ocher ( ) 1
{ 2
sommet Tas. r ecoi t ( pi oche. f i r st ( ) ) ; / / l e sommet de l a pi oche passe sur l e t as 3
pi oche. pop_f r ont ( ) ; / / el l e n' est donc pl us dans l a pi oche 4
i nt r est e = pi oche. count ( ) ; 5
LCDr est e- >di spl ay( r est e) ; 6
i f ( r est e == 0) 7
b_pi oche- >hi de( ) ; / / l a f onct i on hi de( ) per met de masquer un wi dget 8
} 9

Ajoutez la fonction pi ocher ( ) votre classe de dialogue .
J-L Pris - 22/08/05
VC++ 6.0 - Qt 3.2 TD 8 : La patience des pharaons 9/10
4 - La classe CCar t e
Ajoutez une classe CCar t e votre projet . La mise au point de la classe de dialogue nous a
conduit faire cinq "promesses" concernant cette classe :

Origine Nature de la promesse
1 TD08Di al ogI mpl ( ) voi d devi ent ( i nt val eur , QSt r i ng chemi nFi chi er )
2 TD08Di al ogI mpl ( ) voi d associ eBout on( QBut t on *b, bool vi si bl e)
3 descendr e( ) i nt val eur ( ) ;
4 descendr e( ) voi d r ecoi t ( CCar t e & aut r e)
5 descendr e( ) voi d mont r eToi ( )
Dfinition de la classe
On peut satisfaire ces exigences en munissant la classe CCar t e de trois variables membre :
- Un i nt pour la valeur de la carte reprsente (points 1 et 3).
- Une QPi xmap pour l'image reprsentant la carte (points 1 et 5).
- Un "pointeur sur QBut t on" pour stocker l'adresse du bout on ventuellement associ la carte
(points 2 et 5).

Si l'on ajoute ces trois variables les cinq fonctions explicitement requises par le cahier des
charges, la classe CCar t e devra tre dfinie ainsi

:

#i ncl ude " qst r i ng. h" 1
#i ncl ude " qbut t on. h" 2
#i ncl ude " qpi xmap. h" 3

cl ass CCar t e 4
{ 5
publ i c: 6
i nt val ; 7
QPi xmap i mage; 8
QBut t on * l aCase; 9
/ / f onct i ons membr e
voi d devi ent ( i nt v, QSt r i ng chemi n) ; 10
voi d associ eBout on( QBut t on *b, bool vi si bl e) ; 11
i nt val eur ( ) const { r et ur n val ; } / / cet t e f onct i on est df i ni e i ci mme 12
voi d r ecoi t ( CCar t e & aut r e) ; 13
voi d mont r eToi ( ) ; 14
}; 15
La fonction devi ent ( )
Le rle de cette fonction est de transfrer la valeur de ses paramtres dans les variables membre
correspondante (3-4), mais une prcaution doit tre prise : le membre l aCase doit recevoir une
valeur indiquant qu'il ne pointe pour l'instant sur aucun QBut t on (c'est la fonction
associ eBout on( ) qui est charge de donner ce membre une valeur valide, et elle n'est pas
appele pour toutes les cartes : celles de la pioche ne sont jamais associes aucun bouton).
Dans le cas des pointeurs, la valeur nulle (0) sert manifester qu'ils ne dsignent aucun objet, et
la tradition veut que, dans ce contexte, zro s'crive NULL.

voi d CCar t e: : devi ent ( i nt v, QSt r i ng chemi n) 1
{ 2
val = v; 3
i mage. l oad( chemi n) ; 4
l aCase = NULL; / / donne au poi nt eur l a val eur 0 5
} 6

Ajoutez la dfinition de la fonction CCar t e: : devi ent ( ) votre fichier carte.cpp .
La fonction associ eBout on( )
Cette fonction reoit deux arguments : le premier est simplement l'adresse qui doit tre stocke
dans le membre l aCase (3), et le second indique si la carte doit tre rendue visible. Dans ce
programme, les boutons associs des cartes non visibles doivent tre dsactivs (4), faute de
J-L Pris - 22/08/05
VC++ 6.0 - Qt 3.2 TD 8 : La patience des pharaons 10/10
quoi le joueur pourrait essayer de descendre les cartes correspondantes sans attendre qu'elles
soient dbloques. Si la carte doit tre visible, il faut, videmment, qu'elle apparaisse (5-6).

voi d CCar t e: : associ eBout on( QBut t on *b, bool vi si bl e) 1
{ 2
l aCase = b; 3
l aCase- >set Enabl ed( vi si bl e) ; 4
i f ( vi si bl e) 5
mont r eToi ( ) ; 6
} 7

Ajoutez la dfinition de la fonction CCar t e: : associ eBout on( ) votre fichier carte.cpp .
La fonction val eur ( )
Le seul commentaire que mrite cette fonction (dfinie dans le .h) est une justification nergique
de son existence : l'exprience montre que tout va beaucoup mieux si l'on s'interdit absolument
d'accder aux variables membre autrement qu'en passant par une fonction membre.

Dans la version actuelle de notre programme, seule la fonction TD08Di al ogI mpl : : descendr e( )
fait appel la fonction CCar t e: : val eur ( ) , pour dterminer si le mouvement est lgal :
i nt di f f er ence = abs( pyr ami des[ qui ] . val eur ( ) - sommet Tas. val eur ( ) ) ;
Il pourrait sembler plus simple d'accder directement la variable membre concerne, ce qui
viterait d'avoir crer la fonction val eur ( ) :
i nt di f f er ence = abs( pyr ami des[ qui ] . val - sommet Tas. val ) ;
Cette approche est dconseille, car elle conduit placer le nom, le type et la signification d'une
variable membre de CCar t e dans le cahier des charges de cette classe. A l'usage, il s'avre plus
souple et plus sr de n'exprimer les cahiers des charges des classes qu'en termes de fonctions.

La fonction r ecoi t ( )
En plus des transferts de donnes qui transforment la carte rceptrice en une copie de l'autre
carte (3-4), cette fonction garantit l'affichage de la nouvelle valeur de la carte rceptrice (5) et la
disparition de l'autre (6-7) :

voi d CCar t e: : r ecoi t ( CCar t e & aut r e) 1
{ 2
val = aut r e. val ; 3
i mage = aut r e. i mage; 4
mont r eToi ( ) ; 5
i f ( aut r e. l aCase ! = NULL) 6
aut r e. l aCase- >hi de( ) ; 7
} 8

Ajoutez la dfinition de la fonction CCar t e: : r ecoi t ( ) votre fichier carte.cpp .
La fonction mont r eToi ( )
Une carte ne peut se montrer que si un bouton lui a t associ (3-4) et, dans ce jeu, un bouton
sur lequel la carte est visible doit tre rendu actif (5). Pour rendre l'image visible, il suffit de la
transmettre au bouton l'aide de la fonction set Pi xmap( ) (6) :

voi d CCar t e: : mont r eToi ( ) 1
{ 2
i f ( l aCase == NULL) 3
r et ur n; 4
l aCase- >set Enabl ed( t r ue) ; 5
l aCase- >set Pi xmap( i mage) ; 6
} 7

Ajoutez la dfinition de la fonction CCar t e: : mont r eToi ( ) votre fichier carte.cpp .
5 - Exercice
En vous inspirant du code que nous venons de dcrire, crez un programme qui permette de faire
plusieurs parties de suite sans avoir le relancer.
J-L Pris - 22/08/05

Vous aimerez peut-être aussi