Vous êtes sur la page 1sur 11

Centre Informatique pour les Lettres

et les Sciences Humaines


TD 10 : Bataille navale





1 - Analyse pralable ............................................................................................................... 2
2 - Cration du projet et dessin de l'interface ........................................................................... 2
3 - Les types ENat ur e et EDegat s ............................................................................................ 3
4 - La classe dialogue............................................................................................................... 3
Constructeur .................................................................................................................. 3
La fonction f _nouvel l ePar t i e( ) ................................................................................... 4
La fonction i nvent ai r e( ) .............................................................................................. 4
La fonction f _f eu( ) ....................................................................................................... 5
La fonction coul eur ( ) .................................................................................................... 5
Qu'avons-nous promis ? ................................................................................................. 6
5 - La classe CBat ai l l e .......................................................................................................... 6
La fonction i nst al l e( ) .................................................................................................. 6
La fonction nombr eDe( ) .................................................................................................. 7
La fonction eval ueConsequences( ) ............................................................................... 7
Le fichier bataille.h............................................................................................................. 8
Qu'avons-nous promis ? ................................................................................................. 8
6 - La classe CBat eau .............................................................................................................. 8
Le constructeur trois paramtres ................................................................................. 8
La fonction encai sse( ) .................................................................................................. 9
Le fichier bateau.h.............................................................................................................. 9
Qu'avons-nous promis ? ................................................................................................10
7 - La classe CVer di ct ...........................................................................................................10
La fonction message( ) ...................................................................................................10
Le fichier verdict.h.............................................................................................................10
8 - Exercices...........................................................................................................................11


Document du 04/01/06 - Retrouvez la version la plus rcente sur http://www.up.univ-mrs.fr/wcpp
VC++ 6.0 - Qt 3.2 TD 10 : Bataille navale 2/11
Ce TD propose une version informatise du jeu de
bataille navale. Outre qu'il s'agit ici de jouer
contre l'ordinateur, cette version se distingue de
celle bien connue de tous les coliers par le fait
que, lorsqu'on tire dans l'eau, on obtient en
rponse la distance du bateau le plus proche.

Cette information augmente la part de rflexion
intervenant dans le jeu et conduit tenir des
raisonnements proches de ceux suivis dans un
autre jeu bien connu, le dmineur. La similarit
entre ces jeux est renforce par l'adoption d'une
interface analogue : on tire en cliquant sur une
case et, lorsqu'on tire dans l'eau, la surface dont
on apprend qu'elle ne comporte aucun bateau
change de couleur.

Le programme ralis au cours du TD 10
1 - Analyse pralable
La mise au point de ce jeu va nous permettre d'illustrer l'intrt qu'il y a observer
scrupuleusement l'un des grands principes gnraux de la programmation :

La gestion de l'interface utilisateur et le traitement du problme doivent tre pris en charge par
des parties du programme aussi indpendantes l'une de l'autre que possible.

Nous allons donc commencer par crire les fonctions de la classe de dialogue, en veillant ne rien
y traiter qui ne soit directement li l'interface utilisateur. Ceci nous conduira supposer
l'existence d'autres classes, offrant des fonctions qui traitent rellement le problme
(positionnement des bateaux, calcul des consquences d'un tir, etc). Une fois cette classe mise au
point, la liste des suppositions faites nous guidera pour la rdaction du reste du programme.
2 - Cration du projet et dessin de l'interface
En vous inspirant de la procdure dcrite dans l'aide mmoire, crez un projet nomm TD10 .

Placez, dans la partie gauche du dialogue, les widgets suivants :

- Un TextEdit (menu Tools, catgorie Input) nomm message .

- Un PushButton [Nouvelle partie] nomm b_nouvel l ePar t i e .

- Un LCDNumber nomm nb_coups .

Le jeu n'a aucun intrt si le joueur n'essaie pas de minimiser le nombre de coups utiliss pour
liminer compltement la flotte adverse. Il est donc ncessaire de rendre ce nombre visible.

- Cinq LCDNumber (menu Tools, catgorie Display) respectivement nomms nb_sm, nb_t or p,
nb_cui r , nb_cr oi et nb_pa . Ces widgets vont permettre au joueur de connatre le nombre de
bateaux restant en jeu.

A ct de chacun de ces QLCDNumber, placez une srie de frames (menu Tools, catgorie
Containers) indiquant le nombre de cases occupes par le type de bateau correspondant .
Changez la proprit paletteBackgroundColor des frames, pour donner chaque type de bateau
une couleur diffrente .

Dans chacune de ces sries, donnez l'une des frames un nom voquant le type de bateau (sm,
t or p, cui r , cr oi et pa) . Le programme pourra ainsi retrouver facilement la couleur devant
tre utilise pour dessiner chaque type de bateau.

- Cinq GroupBox (menu Tools, catgorie Containers) avec les captions convenables, pour rendre
l'interface plus intelligible pour l'utilisateur .

Dans la partie droite du dialogue, placez une Table (menu Tools, catgorie Views) nomme mer .
Modifiez les proprits numRows et numCols pour obtenir un espace de jeu convenable .

Le jeu n'a d'intrt que si la mer comporte plusieurs centaines de cases (15 x 15, par exemple).
La largeur des colonnes sera rgle par le programme, ne vous en occupez pas pour l'instant.
J-L Pris - 04/01/06
VC++ 6.0 - Qt 3.2 TD 10 : Bataille navale 3/11
Crez un slot f _nouvel l ePar t i e( )

et associez-le au clic sur le bouton [Nouvelle partie] .

Crez un slot f _f eu( i nt , i nt , i nt , const QPoi nt &)

et associez le au clic sur la mer .


3 - Les types ENat ur e et EDegat s
La bataille navale est une question de dgts de gravit variable infligs des bateaux de
diffrents types. Nous avons donc tout intrt disposer de types permettant de manipuler
explicitement ces informations. Crez un fichier typesenum.h et donnez lui le contenu suivant :

#pr agma once 1
enumENat ur e {AUCUN, SOUS_MARI N, TORPI LLEUR, CUI RASSE, CROI SEUR, PORTE_AVI ONS}; 2
enumEDegat s {RATE, TOUCHE, COULE}; 3
4 - La classe dialogue
La gestion de l'interface implique diverses mises jour de l'affichage, dont la plupart sont triviales
(nombres de coups et de bateaux, messages). La fonction associe au clic sur la mer est moins
simple : une fois le coup transmis l'objet qui gre la bataille, il faut dcolorer les cellules
entourant le point d'impact, dans un rayon qui nous sera communiqu en rponse notre coup.

Calculer les consquences du coup propos ne relve videmment pas de la classe de dialogue :
ces consquences sont totalement indpendantes du type d'interface utilisateur mise en place.
Le changement de couleur de la zone dont on sait qu'elle est vide relve, en revanche, d'un pur
choix de type d'interface : le jeu est tout fait jouable (mais plus difficile) si l'interface se
contente d'afficher au point d'impact un nombre indiquant la distance du bateau le plus proche.
Constructeur
Lorsque le programme est lanc, plusieurs oprations doivent tre effectues : il faut
- fixer une fois pour toute la couleur utilise pour reprsenter les cellules dont on ne sait rien ;
- amorcer le gnrateur de nombres pseudo-alatoires (3) (cf. Annexe 2) ;
- ajuster la largeur des colonnes de la QTabl e (4-6) ;
- spcifier les effectifs initiaux des diffrentes catgories de bateaux (7-11) ;
- prparer une nouvelle partie. Comme cette dernire opration devra galement tre faite entre
deux parties successives, le code correspondant prend logiquement place dans la fonction lie
au bouton [Nouvelle partie], fonction qui est donc appele (12) par le constructeur.

Ajoutez deux membres votre classe de dialogue : une variable de type QMap<ENat ur e, i nt >
nomme m_ef f ect i f s et une constante de type QCol or nomme m_coul eur Mer .

Donnez au corps du constructeur le contenu suivant

:

TD10Di al ogI mpl : : TD10Di al ogI mpl ( QWi dget * par ent , const char * name, bool modal , WFl ags f ) 1
: TD10Di al og( par ent , name, modal , f ) , m_coul eur Mer ( QCol or ( 169, 210, 212) )
{ 2
sr and( t i me( NULL) ) ; / / amor age du gnr at eur de nombr es pseudo- al at oi r es 3
i nt col ; 4
f or ( col =0 ; col < mer - >numCol s( ) ; ++col ) 5
mer - >set Col umnWi dt h( col , 24) ; / / l es col onnes ont une l ar geur de 24 pi xel s 6
m_ef f ect i f s[ PORTE_AVI ONS] = 1; 7
m_ef f ect i f s[ CROI SEUR] = 2; 8
m_ef f ect i f s[ CUI RASSE] = 2; 9
m_ef f ect i f s[ TORPI LLEUR] = 3; 10
m_ef f ect i f s[ SOUS_MARI N] = 3; 11
f _nouvel l ePar t i e( ) ; 12
} 13

Remarquez l'usage de la liste d'initialisation, qui permet d'initialiser la constante m_coul eur Mer .
La valeur utilise pour cette initialisation est elle-mme gnre en appelant explicitement un
constructeur de la classe QCol or .
J-L Pris - 04/01/06
VC++ 6.0 - Qt 3.2 TD 10 : Bataille navale 4/11
La fonction f _nouvel l ePar t i e( )
Cette fonction doit d'une part mettre la QTabl e dans un tat reprsentant le dbut de partie et,
d'autre part, demander la rinitialisation du jeu. La premire partie de la fonction est trs simple :

voi d TD10Di al ogI mpl : : f _nouvel l ePar t i e( ) 1
{ 2
i nt col ; 3
i nt l i gne; 4
f or ( l i gne = 0 ; l i gne < mer - >numRows( ) ; ++l i gne) 5
f or ( col = 0 ; col < mer - >numCol s( ) ; ++col ) 6
{ 7
mer - >cl ear Cel l ( l i gne, col ) ; 8
QPi xmap maPi xmap ( mer - >col umnWi dt h( col ) , mer - >r owHei ght ( l i gne) ) ; 9
maPi xmap. f i l l ( m_coul eur Mer ) ; 10
mer - >set Pi xmap( l i gne, col , maPi xmap) ; 11
} 12

Ce fragment de code utilise cinq fonctions membre de la classe QTabl e. Si le rle et l'utilisation
des quatre premires semblent vidents, la dernire implique l'utilisation d'une instance de la
classe QPi xmap. Cette classe est l'une de celles proposes par Qt pour manipuler les images.
Dans le cas prsent, il s'agit simplement d'une image ayant exactement la taille de la cellule
concerne (9) et uniformment revtue de la couleur choisie.

La seconde partie de la fonction utilise une autre variable membre, m_l eJ eu, qui est une instance
de la classe CBat ai l l e que nous allons crer pour grer la partie. Cette classe devra disposer
d'une fonction i nst al l e( ) ayant pour effet de choisir les positions, dans l'instance au titre de
laquelle elle est excute, des bateaux d'une flotte dont les effectifs lui sont communiqus par un
premier argument, en respectant les limites de l'espace de jeu indiques par le second argument.

Ce second argument est une valeur de type QPoi nt , obtenue par appel explicite d'un
constructeur de cette classe (la classe QPoi nt est une classe trs simple, spcialement prvue
pour permettre le stockage de couples du type abscisse/ordonne).

message- >set Text ( " Pour t i r er , cl i quez sur une case" ) ; 13
m_par t i eEnCour s = m_l eJ eu. i nst al l e( m_ef f ect i f s, 14
1
QPoi nt ( mer - >numRows( ) , mer - >numCol s( ) ) ) ;
i f ( ! m_par t i eEnCour s) 15
message- >set Text ( " I l n' y a pas assez pl ace pour l es bat eaux ! " ) ; 16
i nvent ai r e( ) ; 17
} 18

Il n'est pas certain que la fonction i nst al l e( ) parvienne effectuer sa tche : si les dimensions
qui lui sont passes sont trop faibles, elle risque de ne pas parvenir positionner tous les
bateaux requis. Elle signalera alors cet tat de fait en renvoyant f al se, et il appartient la
fonction appelante de prvoir les mesures ncessaires dans ce cas (15-16).

Ajoutez au dialogue une fonction f _t i r age( ) dfinie comme suggr ci-dessus , une variable
boolenne nomme m_par t i eEnCour s et une variable de type CBat ai l l e nomme m_l eJ eu

.
La fonction i nvent ai r e( )
Le seul intrt du code de cette fonction est qu'il rvle de nouvelles exigences quant l'interface
de la classe CBat ai l l e : elle devra comporter deux fonctions membre capables de renvoyer l'une
le nombre de coups tirs et l'autre le nombre d'exemplaires restants d'un type de bateaux.

voi d TD10Di al ogI mpl : : i nvent ai r e( ) 1
{ 2
nb_coups- >di spl ay( m_l eJ eu. nombr eDeCoups( ) ) ; 3
2
nb_sm- >di spl ay( m_l eJ eu. nombr eDe( SOUS_MARI N) ) ; 4
nb_t or p- >di spl ay( m_l eJ eu. nombr eDe( TORPI LLEUR) ) ; 5
nb_cui r - >di spl ay( m_l eJ eu. nombr eDe( CUI RASSE) ) ; 6
3
nb_cr oi - >di spl ay( m_l eJ eu. nombr eDe( CROI SEUR) ) ; 7
nb_pa- >di spl ay( m_l eJ eu. nombr eDe( PORTE_AVI ONS) ) ; 8
} 9

Ajoutez la fonction i nvent ai r e( ) votre classe de dialogue .
J-L Pris - 04/01/06
VC++ 6.0 - Qt 3.2 TD 10 : Bataille navale 5/11
La fonction f _f eu( )
La premire partie de cette fonction est assez simple : on tire, et on modifie la case d'impact pour
rendre compte de l'effet du coup :

voi d TD10Di al ogI mpl : : f _f eu( i nt l i gneI mpact , i nt col I mpact , i nt , const QPoi nt &) 1
{/ / on t i r e 2
i f ( ! m_par t i eEnCour s) 3
r et ur n; 4
CVer di ct ef f et = m_l eJ eu. eval ueConsequences( QPoi nt ( col I mpact , l i gneI mpact ) ) ; 5
4
/ / t r ai t ement de l a case d' i mpact
mer - >cl ear Cel l ( l i gneI mpact , col I mpact ) ; / / el l e passe donc en bl anc 6
const i nt r ayon = ef f et . di st ance( ) ; 7
i f ( ef f et . vi ct i me( ) == AUCUN) 8
mer - >set Text ( l i gneI mpact , col I mpact , QSt r i ng: : number ( r ayon) ) ; 9
5
6
el se 10
{ 11
QPi xmap pi xI mpact ( mer - >col umnWi dt h( col I mpact ) , mer - >r owHei ght ( l i gneI mpact ) ) ; 12
swi t ch( ef f et . vi ct i me( ) ) 13
{/ / choi x d' une coul eur 14
case SOUS_MARI N: pi xI mpact . f i l l ( sm- >pal et t eBackgr oundCol or ( ) ) ; br eak; 15
case TORPI LLEUR: pi xI mpact . f i l l ( t or p- >pal et t eBackgr oundCol or ( ) ) ; br eak; 16
case CUI RASSE: pi xI mpact . f i l l ( cui r - >pal et t eBackgr oundCol or ( ) ) ; br eak; 17
case CROI SEUR: pi xI mpact . f i l l ( cr oi - >pal et t eBackgr oundCol or ( ) ) ; br eak; 18
case PORTE_AVI ONS: pi xI mpact . f i l l ( pa- >pal et t eBackgr oundCol or ( ) ) ; br eak; 19
def aul t : pi xI mpact . f i l l ( QCol or ( 0, 0, 0) ) ; br eak; 20
} 21
mer - >set Pi xmap( l i gneI mpact , col I mpact , pi xI mpact ) ; / / el l e se t ei nt e 22
} 23

Ce fragment de code suppose une fonction CBat ai l l e::eval ueConsequences( ) renvoyant une
description de l'effet d'un coup. Comme cet effet est complexe (il faut indiquer soit le type du
bateau et la nature des dgts, soit la distance du bateau le plus proche), la fonction renvoie une
valeur de type CVer di ct , une classe qu'il faudra crer. Nous exigeons que les fonctions
CVer di ct : : di st ance( ) (7) et CVer di ct : : vi ct i me( ) (8, 13) fournissent l'information que
leur nom suggre.

Dans la seconde partie de la fonction f _f eu( ) , les cellules voisines du point d'impact doivent
changer de couleur. Il faut traiter correctement le cas o l'impact est proche des limites du jeu,
ainsi que celui o la zone traiter comporte des traces de bateaux dj couls : pour prserver
ces traces, seules les cellules qui ont encore la couleur de la mer sont blanchies.

/ / bl anchi t l a zone dont on vi ent d' appr endr e qu' el l e est vi de
i nt x; 24
i nt y; 25
f or ( y = l i gneI mpact + 1 - r ayon ; y < l i gneI mpact + r ayon ; ++y) 26
i f ( y >= 0 && y < mer - >numRows( ) ) 27
f or ( x = col I mpact + 1 - r ayon ; x < col I mpact + r ayon ; ++x) 28
i f ( x >= 0 && x < mer - >numCol s( ) && coul eur ( mer , y, x) == m_coul eur Mer ) 29
mer - >cl ear Cel l ( y, x) ; 30
/ / concl usi on
message- >set Text ( ef f et . message( ) ) ; 31
m_par t i eEnCour s = ! ef f et . par t i eGagnee( ) ; 32
8
7
i nvent ai r e( ) ; 33
} 34

Ajoutez la fonction f _f eu( ) votre dialogue et notez que CVerdict devra proposer deux autres
fonctions : message( ) doit renvoyer une QSt r i ng dcrivant la situation reprsente par l'instance
au titre de laquelle elle est excute et par t i eGagnee( ) doit renvoyer un boolen.
La fonction coul eur ( )
Dterminer la "couleur d'une cellule" de la QTabl e n'est pas immdiat, car il s'agit de la couleur
de la pixmap qui est dans la cellule, et la classe QPi xmap n'offre pas de fonction renvoyant "la"
couleur de l'objet concern (les pixmap ont habituellement plusieurs couleurs). Si la cellule
contient une pixmap (3) , elle permet d'accder celle-ci, d'en demander la conversion en un
J-L Pris - 04/01/06
VC++ 6.0 - Qt 3.2 TD 10 : Bataille navale 6/11
objet permettant d'accder son contenu, puis d'accder l'un des pixels (nous savons qu'ils sont
tous identiques). La valeur reprsentant ce pixel est un i nt dont seuls les trois octets de poids
faible nous intressent (ce sont les composantes rouge, verte et bleue de la couleur du pixel). Pour
obtenir un codage identique celui d'une QCol or , il faut forcer 1 les bits de l'octet de poids fort.

QCol or TD10Di al ogI mpl : : coul eur ( const QTabl e *t , i nt l , i nt c) const 1
{ 2
i f ( t - >i t em( l , c) ! = NULL && ! t - >i t em( l , c) - >pi xmap( ) . i sNul l ( ) ) 3
r et ur n t - >i t em( l , c) - >pi xmap( ) . conver t ToI mage( ) . pi xel ( 1, 1) | 0xf f 000000; 4
r et ur n - 1; 5
} 6

Ajoutez la fonction coul eur ( ) votre classe de dialogue
Qu'avons-nous promis ?
Le tableau suivant rcapitule les suppositions que nous avons ts conduits faire pour pouvoir
dfinir confortablement les fonctions membre de notre classe de dialogue :

Origine Nature de la promesse
1 f _t i r age( ) bool CBat ai l l e: : i nst al l e( QMap<ENat ur e, i nt >, QPoi nt )
2 i nvent ai r e( ) i nt CBat ai l l e: : nombr eDeCoups( )
3 i nvent ai r e( ) i nt CBat ai l l e: : nombr eDe( ENat ur e)
4 f _f eu( ) CVer di ct CBat ai l l e: : eval ueConsequences( QPoi nt )
5 f _f eu( ) i nt CVer di ct : : di st ance( )
6 f _f eu( ) ENat ur e CVer di ct : : vi ct i me( )
7 f _f eu( ) QSt r i ng CVer di ct : : message( )
8 f _f eu( ) bool CVer di ct : : par t i eGagnee( )
5 - La classe CBat ai l l e
Ajoutez une classe CBat ai l l e votre projet .

La fonction i nst al l e( )
La fonction i nst al l e( ) commence par remettre zro un compteur de coups (3) et la collection
de bateaux (4). Cette collection est une simple QVal ueLi st de CBat eau, une classe que nous
allons crer pour reprsenter nos cibles. Ds que la zone de jeu n'est plus vide, il faut veiller ce
qu'un nouveau bateau ne prtende pas occuper une case dj utilise. La fonction i nst al l e( )
gre ce problme en mettant en place (5) une liste des positions qui ne sont plus libres :
9

bool CBat ai l l e: : i nst al l e( const QMap<ENat ur e, i nt > & ef f ect i f s, QPoi nt max) 1
{ 2
m_nbCoups = 0; 3
m_l aFl ot t e. cl ear ( ) ; 4
QVal ueLi st <QPoi nt > occupes; 5

Le parcours de la QMap ef f ect i f s permet ensuite de savoir, pour chaque type de bateau,
combien d'exemplaires doivent tre positionns, c'est dire ajouts la flotte.

La valeur transmise append( ) est obtenue par appel explicite d'un constructeur de CBateau,
qui choisira une position pour le nouveau bateau. Ce choix exige videmment que l'on indique
au constructeur la nature du bateau, les positions dj occupes et les limites du jeu.

QMap<ENat ur e, i nt >: : Const I t er at or i t ; 6
f or ( i t = ef f ect i f s. begi n( ) ; i t ! = ef f ect i f s. end( ) ; ++i t ) 7
{ 8
i nt n; 9
f or ( n=0 ; n < i t . dat a( ) ; ++n) 10
m_l aFl ot t e. append( CBat eau( i t . key( ) , occupes, max) ) ; 11
10
i f ( nombr eDe( i t . key( ) ) ! = i t . dat a( ) ) 12
r et ur n f al se; / / on a manqu de pl ace ! 13
} 14
r et ur n t r ue; 15
} 16

J-L Pris - 04/01/06
VC++ 6.0 - Qt 3.2 TD 10 : Bataille navale 7/11
La mise en place d'un bateau peut chouer (par manque de place). Aprs avoir ajout le nombre
de bateaux prvus pour le type en cours de fabrication (9-11), nous vrifions donc qu'ils sont
tous oprationnels (12-13). Cette vrification est simplifie en exigeant que, en cas d'chec, le
constructeur de CBat eau laisse l'objet sur lequel il oprait dans un tat qui le rend invisible pour
nombr eDe( ) .

Ajoutez votre classe CBat ai l l e les variables m_nbCoups (de type i nt ) et m_l aFl ot t e , ainsi
que la fonction que nous venons de dcrire .
La fonction nombr eDe( )
Cette fonction se contente de parcourir la flotte en incrmentant un compteur chaque fois que le
bateau rencontr correspond au type sur lequel porte la question. Elle exige donc que la classe
CBat eau offre une fonction nat ur e( ) renvoyant le type du bateau au titre duquel elle est appele.

i nt CBat ai l l e: : nombr eDe( ENat ur e l eTypeQui NousI nt er esse) const 1
{ 2
i nt ef f ect i f = 0; 3
QVal ueLi st <CBat eau>: : Const I t er at or i t ; 4
f or ( i t = m_l aFl ot t e. begi n( ) ; i t ! = m_l aFl ot t e. end( ) ; ++i t ) 5
i f ( ( *i t ) . nat ur e( ) == l eTypeQui NousI nt er esse) 6
++ef f ect i f ; 7
r et ur n ef f ect i f ; 8
} 9
11

Ajoutez la fonction nombr eDe( ) votre classe CBat ai l l e
La fonction eval ueConsequences( )
Le rle principal de cette fonction est de transmettre les coordonnes du point d'impact chacun
des bateaux de la flotte (8). Si un bateau est atteint (ie. TOUCHE ou COULE), la fonction s'achve
immdiatement en renvoyant son verdict (19).

La fonction eval ueConsequences( ) doit aussi grer la flotte (15-17) et, en cas de "coup dans
l'eau", calculer la distance du bateau le plus proche. Ce calcul exige que chaque bateau place sa
propre distance au point d'impact dans la rponse qu'il fournit un tir : il suffit d'utiliser une
variable (4) pour capturer (12-13) la plus petite des valeurs observes. C'est cette valeur qui doit,
si aucun bateau n'est atteint, figurer dans le verdict final (22).

CVer di ct CBat ai l l e: : eval ueConsequences( QPoi nt i mpact ) 1
{ 2
++m_nbCoups; 3
i nt di st anceMi ni = I NT_MAX; 4
QVal ueLi st <CBat eau>: : I t er at or i t ; 5
f or ( i t = m_l aFl ot t e. begi n( ) ; i t ! = m_l aFl ot t e. end( ) ; ++i t ) 6
{ 7
CVer di ct r esul t at = ( *i t ) . encai sse( i mpact ) ; 8
12
swi t ch( r esul t at . gr avi t e( ) ) 9
{ 10
case RATE : 11
i f ( r esul t at . di st ance( ) < di st anceMi ni ) 12
di st anceMi ni = r esul t at . di st ance( ) ; 13
br eak; 14
case COULE : 15
m_l aFl ot t e. r emove( i t ) ; 16
r esul t at . par t i eGagnee( m_l aFl ot t e. i sEmpt y( ) ) ; 17
13
case TOUCHE : 18
r et ur n r esul t at ; 19
} 20
} 21
r et ur n CVer di ct ( AUCUN, RATE, di st anceMi ni ) ; 22
} 23

La classe CBat eau doit offrir une fonction encai sse( ) renvoyant un CVer di ct qui dcrit l'effet
d'un tir dans la case dsigne par son paramtre sur le bateau au titre duquel elle est invoque.

Ajoutez la fonction encai sse( ) votre classe CBat ai l l e .
J-L Pris - 04/01/06
VC++ 6.0 - Qt 3.2 TD 10 : Bataille navale 8/11
Le fichier bataille.h
Une fois ajoute la dfinition (7) de la fonction nombr eDeCoups( ) , la dfinition de la classe
CBat ai l l e prend finalement l'allure suivante :

#i ncl ude " qmap. h"
#i ncl ude " t ypesenum. h"
#i ncl ude " bat eau. h"
#i ncl ude " ver di ct . h"

cl ass CBat ai l l e 1
{ 2
publ i c: 3
bool i nst al l e( const QMap<ENat ur e, i nt > & ef f ect i f s, QPoi nt max) ; 4
CVer di ct eval ueConsequences( QPoi nt i mpact ) ; 5
i nt nombr eDe( ENat ur e l equel ) const ; 6
i nt nombr eDeCoups( ) const {r et ur n m_nbCoups; } 7
pr ot ect ed: 8
i nt m_nbCoups; 9
QVal ueLi st <CBat eau> m_l aFl ot t e; 10
}; 11

Vrifiez que l'interface de la classe CBat ai l l e tient toutes les promesses faites son sujet .
Qu'avons-nous promis ?
Origine Nature de la promesse
9 m_l aFl ot t e CBat eau: : CBat eau( )
10 i nst al l e( ) CBat eau: : CBat eau( ENat ur e, QVal ueLi st <QPoi nt > &, QPoi nt )
11 nombr eDe( ) ENat ur e CBat eau: : nat ur e( )
12 encai sse( ) CVer di ct CBat eau: : encai sse( QPoi nt )
13 encai sse( ) voi d CVer di ct : : par t i eGagnee( bool )
6 - La classe CBat eau
Ajoutez une classe CBat eau votre projet .

Un CBat eau devant tre capable d'indiquer son type (promesse 11), il semble naturel de munir la
classe d'une variable membre m_nat ur e de type ENat ur e qui permettra de stocker cette
information . La liste des cases qu'il occupe doit, elle aussi, tre stocke dans un CBat eau.
Ajoutez donc cette classe une variable de type QVal ueLi st de QPoi nt nomme m_l esCases .
Le constructeur trois paramtres
Cette fonction est celle qui effectue l'opration la plus dlicate : le positionnement d'un bateau
dans l'espace de jeu. La stratgie utilise est de tirer au hasard (17) une orientation (horizontale
ou verticale) et une case (18-20), puis de vrifier que toutes les cases convoites sont disponibles
(21-26). Si ce n'est pas le cas, une nouvelle case est tire (dans la limite de 100 tentatives). Etant
donn qu'un bateau occupe plusieurs cases, il serait vain d'essayer d'en positionner un en
partant trop prs des limites de l'espace de jeu. Le tirage de la position s'effectue donc dans un
espace rduit d'une mar ge dont la taille dpend du type du bateau installer (3-11). Cette marge
est soustraite la largeur de l'espace de jeu si une orientation horizontale a t choisie, et sa
hauteur dans le cas contraire.

CBat eau: : CBat eau( ENat ur e quoi , QVal ueLi st <QPoi nt > & i nt er di t s, QPoi nt max) : 1
m_nat ur e( AUCUN) / / a ne ser a un " quoi " que si on ar r i ve l e const r ui r e. . .
{ 2
i nt mar ge; / / l es bat eaux occupent mar ge+1 cases 3
swi t ch( quoi ) 4
{/ / l es bat eaux de pl us d' une case doi vent commencer assez l oi n du bor d 5
case PORTE_AVI ONS : mar ge = 4; br eak; 6
case CROI SEUR : mar ge = 3; br eak; 7
case CUI RASSE : mar ge = 2; br eak; 8
case TORPI LLEUR : mar ge = 1; br eak; 9
def aul t : mar ge = 0; br eak; / / l es SOUS_MARI N et l es i mpr vus. . . 10
} 11
J-L Pris - 04/01/06
VC++ 6.0 - Qt 3.2 TD 10 : Bataille navale 9/11
i nt t i r ages = 0; 12
whi l e ( m_l esCases. count ( ) < 1 + mar ge) 13
{ 14
i f ( t i r ages++ > 100) 15
r et ur n; / / on n' y ar r i ve pas ! 16
bool hor i zont al = r and( ) %2; 17
/ / choi x de l a case de dpar t
i nt x = r and( ) %( max. x( ) - ( hor i zont al ? mar ge : 0) ) ; 18
i nt y = r and( ) %( max. y( ) - ( hor i zont al ? 0 : mar ge) ) ; 19
QPoi nt posi t i on( x, y) ; 20
/ / vr i f i e que t out es l es cases envi sages sont l i br es
m_l esCases. cl ear ( ) ; 21
whi l e( m_l esCases. count ( ) < 1 + mar ge && ! i nt er di t s. cont ai ns( posi t i on) ) 22
{ 23
m_l esCases. append( posi t i on) ; 24
posi t i on += hor i zont al ? QPoi nt ( 1, 0) : QPoi nt ( 0, 1) ; 25
} 26
} 27
i nt er di t s += m_l esCases; / / l es cases choi si es sont mai nt enant occupes 28
m_nat ur e = quoi ; / / l a mi se en pl ace a r ussi ! 29
} 30

Les cases occupes par le bateau sont enfin ajoutes la liste des cases qui ne sont plus
disponibles (28) et la russite de la construction est signale en confrant au bateau son vritable
type (31).

Si le bateau n'a pas trouv de place, l'excution du constructeur s'achve la ligne 16, et le
CBat eau reste de type AUCUN, ce qui garantit que la fonction nombr eDe( ) ne le prendra pas en
compte lors du dnombrement des exemplaires du type qu'il aurait d avoir.

Ajoutez cette fonction

la classe CBat eau.

La fonction encai sse( )
Lorsqu'un tir survient, un bateau vrifie s'il est concern en parcourant la liste des cases qu'il
occupe. Il mmorise, au passage, la distance minimale observe entre le point d'impact et ces
cases, car cette information doit faire partie de la conclusion qu'il renvoie.

CVer di ct CBat eau: : encai sse( QPoi nt i mpact ) 1
{ 2
i nt di st anceMi ni = I NT_MAX; 3
QVal ueLi st <QPoi nt >: : I t er at or i t ; 4
f or ( i t = m_l esCases. begi n( ) ; i t ! = m_l esCases. end( ) ; ++i t ) 5
{ 6
i nt del t aX = abs( i mpact . x( ) - ( *i t ) . x( ) ) ; / / di f f r ence des absci sses 7
i nt del t aY = abs( i mpact . y( ) - ( *i t ) . y( ) ) ; / / di f f r ence des or donnes 8
i nt d = ( del t aX > del t aY) ? del t aX : del t aY; / / l a pl us gr ande des deux 9
i f ( d == 0) 10
{/ / enf er et damnat i on ! 11
m_l esCases. r emove( i t ) ; / / r et i r e l ' l ment dt r ui t 12
r et ur n CVer di ct ( m_nat ur e, m_l esCases. i sEmpt y( ) ? COULE : TOUCHE, 0) ; 13
} 14
i f ( d < di st anceMi ni ) 15
di st anceMi ni = d; 16
} 17
r et ur n CVer di ct ( AUCUN, RATE, di st anceMi ni ) ; 18
} 19
Le fichier bateau.h
Une fois ajoute la fonction encai sse( ) , il ne reste qu' dfinir (8) la fonction nat ur e( )

pour obtenir la version finale de la classe CBat eau :

#i ncl ude " qval uel i st . h"
#i ncl ude " qpoi nt . h"
#i ncl ude " t ypesEnum. h"
J-L Pris - 04/01/06
VC++ 6.0 - Qt 3.2 TD 10 : Bataille navale 10/11
#i ncl ude " ver di ct . h"
cl ass CBat eau 1
{ 2
publ i c: 3
CBat eau( ) : m_nat ur e( AUCUN) {} 4
pr ot ect ed: 5
CBat eau( ENat ur e quoi , QVal ueLi st <QPoi nt > & i nt er di t s, QPoi nt max) ; 6
CVer di ct encai sse( QPoi nt i mpact ) ; 7
ENat ur e nat ur e( ) const {r et ur n m_nat ur e; } 8
QVal ueLi st <QPoi nt > m_l esCases; 9
ENat ur e m_nat ur e; 10

f r i end cl ass CBat ai l l e; 11
}; 12

Remarquez que seules les fonctions membre de CBat ai l l e ont vocation manipuler des
CBat eau. On peut matrialiser cette restriction en rduisant l'extrme l'interface de la classe et
en dclarant amie la classe CBat ai l l e. La cration d'une QVal ueLi st de CBat eau exige
toutefois qu'un constructeur par dfaut reste public et, comme la prsence du constructeur
trois arguments inhibe la cration automatique d'un constructeur par dfaut, il est
indispensable d'en dfinir explicitement un (4).
Qu'avons-nous promis ?
Origine Nature de la promesse
15 encai sse( ) CVer di ct : : CVer di ct ( ENat ur e, EDegat s, i nt )
16 encai sse( ) voi d CVer di ct : : par t i eGagnee( EDegat s)
7 - La classe CVer di ct
Ajoutez une classe CVer di ct votre projet .
La fonction message( )
Ajoutez cette classe la fonction suivante (qui se passe aisment de commentaires)

QSt r i ng CVer di ct : : message( ) const 1
{ 2
QSt r i ng degat s = ( m_gr avi t e == TOUCHE) ? " %1 t ouch" : " %1 coul " ; 3
i f ( m_par t i eGagnee) 4
degat s += " \ nPARTI E GAGNEE ! " ; 5
swi t ch( m_vi ct i me) 6
{ 7
case AUCUN : r et ur n " Dans l ' eau ! " ; 8
case SOUS_MARI N : r et ur n degat s. ar g( " sous- mar i n" ) ; 9
case TORPI LLEUR : r et ur n degat s. ar g( " t or pi l l eur " ) ; 10
case CUI RASSE : r et ur n degat s. ar g( " cui r ass" ) ; 11
case CROI SEUR : r et ur n degat s. ar g( " cr oi seur " ) ; 12
case PORTE_AVI ONS : r et ur n degat s. ar g( " por t e- avi ons" ) ; 13
def aul t : r et ur n " t ype de bat eau i nconnu" ; 14
} 15
} 16
Le fichier verdict.h
Par nature, les instances de CVer di ct sont des objets qui ne permettent que la lecture des
informations qu'ils contiennent. L'interface de cette classe ne contient donc, logiquement, que des
fonctions de lecture. Il se trouve cependant que, dans notre programme, l'instanciation de cette
classe est effectue par quelqu'un (la fonction f _f eu( ) de la classe de dialogue, en l'occurrence)
qui n'est videmment pas en mesure de fixer par initialisation l'tat dfinitif de l'objet cr. Cet
tat est calcul d'une part par l'unique instance de la classe CBat ai l l e (qui est seule pouvoir
dterminer quel est le bateau le plus proche d'un point d'impact et si la partie est termine) et
d'autre part par l'instance de CBat eau qui est ventuellement atteinte par le tir (cet objet est le
seul connatre son propre type et pouvoir dterminer la gravit de sa situation). Pour rendre
ces oprations possibles sans compromettre l'interdiction faite aux fonctions membre de la classe
J-L Pris - 04/01/06
VC++ 6.0 - Qt 3.2 TD 10 : Bataille navale 11/11
de dialogue de modifier l'tat d'un CVer di ct , les classe CBat eau et CBat ai l l e sont dclares
amies (16-17).

#i ncl ude " qst r i ng. h"
#i ncl ude " t ypesenum. h"

cl ass CVer di ct 1
{ 2
publ i c: 3
i nt di st ance( ) const {r et ur n m_di st ance; } 4
bool par t i eGagnee( ) const {r et ur n m_par t i eGagnee; } 5
ENat ur e vi ct i me( ) const {r et ur n m_vi ct i me; } 6
EDegat s gr avi t e( ) const {r et ur n m_gr avi t e; } 7
QSt r i ng message( ) const ; 8
pr ot ect ed: 9
CVer di ct ( ENat ur e v, EDegat s dg, i nt d) : 10
m_vi ct i me( v) , m_gr avi t e( dg) , m_di st ance( d) , m_par t i eGagnee( f al se) {}
voi d par t i eGagnee( bool v) {m_par t i eGagnee = v; } 11
ENat ur e m_vi ct i me; 12
EDegat s m_gr avi t e; 13
i nt m_di st ance; 14
bool m_par t i eGagnee; 15

f r i end cl ass CBat ai l l e; 16
f r i end cl ass CBat eau; 17
}; 18

Compltez la dfinition de la classe CVer di ct , compilez le programme , et amusez-vous
bien
8 - Exercices
1) A quel moment la classe CBat ai l l e est-elle instancie ? Quel est le constructeur qui est
excut cette occasion ?

2) Combien la fonction CVer di ct : : par t i eGagnee( ) a-t-elle de paramtres ?

3) Le constructeur trois paramtres de CVer di ct est protg et n'est donc accessible qu'aux
amies de cette classe. Comment la fonction TD10Di al ogI mpl : : f _f eu( ) peut-elle donc disposer
d'une variable locale de type CVer di ct ? Quelles sont les oprations que cette fonction est en
mesure d'effectuer sur la variable en question ?

4) Modifiez le programme de faon ce que l'utilisateur puisse choisir le nombre de bateaux de
chaque type installs en dbut de partie ainsi que les nombres de lignes et de colonnes de
l'espace de jeu.
J-L Pris - 04/01/06