Vous êtes sur la page 1sur 6

UNIVERSITE DE LA MANOUBA ANNEE UNIVERSITAIRE On se restreint considérablement par rapport au jeu réel, car on ne s’intéresse grosso modo qu’au

blement par rapport au jeu réel, car on ne s’intéresse grosso modo qu’au problème
-----¤¤¤¤----- 2009-2010 d’achat de terrain et de règlement des loyers. Les règles de calcul du montant du loyer que nous retiendrons
ECOLE NATIONALE DES SCIENCES sont les suivantes :
DE L'INFORMATIQUE • Loyer pour une ‘Propriété’ = (2 * loyer de base) si le joueur possède toutes les propriétés du groupe sinon
(loyer de base) ;
• Loyer pour une ‘Compagnie’ = (4 * loyer de base * valeur des dés) si le joueur possède les deux
sition_Correction_Examen 1er semestre
Proposition_Correction_ compagnies du groupe sinon (loyer de base * valeur des dés) ;
(Session Principale – janvier 2010) • Loyer pour une ‘Gare’ = (loyer de base * nombre de gares possédés par le propriétaire de cette gare).
Matière : Conception et Programmation orientées objets Date : vendredi 8 janvier 2010 Le but du jeu consiste à ruiner ses concurrents. Ainsi, un joueur qui n’a plus de capital pour payer un loyer
Niveau : II2 Durée: 2H quitte le jeu. Les terrains dont il était propriétaire redeviennent sans propriétaire. La partie se termine,
Enseignants : Y. JAMOUSSI, I. BEN HAMOUDA, S. MTIBAA, I. FLISS Documents : non autorisés lorsqu’il ne reste qu’un seul joueur dans le jeu.
NB : Toutes les informations décrivant les 40 cases sont stockées dans un fichier texte nommé "cases.txt", une
ligne du fichier par case. Voici un extrait de ce fichier:
• Nombre de pages = Sujet (4( pages) + 2 Formulaires A3 (de 1/8
1/ à 8/8)
• En cas de besoin vous pouvez diviser l’espace réservé à la réponse en deux pass Départ 0 0 0
prop Belleville 6000 200 1 mauve
• Les réponses hors sujet seront notées négativement ... ... ... ... ... ...
comp Électricité 15000 400 12 compagnie
prop Neuilly 14000 1000 13 violet
prop Paradis 16000 1200 14 violet
Problème gare De-Lyon 20000 2500 15 gare
L’objectif de ce problème est l’analyse et l’implémentation,
l’implémentation en partie, d’unee version simplifiée du jeu ... ... ... ... ... ...
"Monopoly". Ce jeu se joue avec un nombre quelconque de joueurs sur un plateau de 40 cases successives, pass Taxe-Luxe 0 0 38
que les joueurs parcourent en sens croissant depuis la case de départ,, et qui sont organisées cycliquement prop De-la-paix 40000 5000 39 indigo
(lorsqu’on atteint la dernière case, on continue sur la première) comme l’illustre la figure ci-dessous.
ci
Chaque ligne du fichier comporte successivement les renseignements suivants : type de la case (pass ou bien
Toutes les cases ont un nom. On compte 12 prop ou bien gare ou bien comp), nom de la case, prix d’achat (0 pour les passages), loyer de base (0 pour les
cases de passage,, déclenchant des actions passages), numéro d’ordre de la case, nom du groupe de terrains.
diverses (transfert de position,, paiement,
encaissement, emprisonnement), ), et 28 cases Lors de l’analyse du jeu Monopoly, un développeur a proposé le diagramme de classes UML incomplet
dites terrains,, pouvant donner lieu à l’achat du suivant :
terrain (s’il
s’il n’a pas de propriétaire),
propriétaire ou a un
paiement/encaissement de loyer. Ce dernier
type de terrain achetable, se subdivise lui- lui
même en 22 propriétés, 4 gares et 2
compagnies (électricité, eaux).
Les 28 terrains sont divisés en 10 ‘groupes
groupes’ :
• Les terrains d’une même couleur forment
un groupe de propriétés. Il existe donc
huit groupes différents de propriétés
(puisqu’il y a huit couleurs).
• Les 4 gares forment le 9ème groupe.
• Les 2 compagnies forment le 10ème
groupe.
Chaque joueur est caractérisé par son nom et son capital d’argent. Dans cee jeu, chaque joueur occupe une
case parmi les 40 cases du plateau.
plateau Il possède un pion, portant son nom, qui marque sa position dans le
plateau. Les différents joueurs démarrent le jeu à la position case de "départ",, et le capital initial de chacun
d’entre eux est de 150000 F. Les joueurs jouent à tour de rôle.. Chaque joueur à son tour lance 2 dés à 6 faces
et progresse son pion d’un nombre de cases égal à la somme des deux dés qu’il a jeté. jeté En fonction de la case
de destination, il se produit l’une
une des actions correspondantes :
• Si la case de destination est un terrain qui n’a pas de propriétaire, le joueur peut l’acheter s’il le souhaite
et s’il dispose du capital nécessaire pour son achat ;
• Si la case de destination est un terrain à la possession d’un
un autre propriétaire, il doit lui payer un loyer ;
• Si la case de destination est un terrain dont il est le propriétaire, rien ne se passe ;
• Si la case de destination est une case de passage différente d’un terrain,
terrain rien ne se passe ;
1/4 2/4
Annexe STL
Le développeur a fait une ébauche de codage en C++ relative aux classes ‘Joueur’ et ‘Case’.
/** Joueur dans le "jeu Monopoly" **/ /** Case du "jeu Monopoly". **/
class Joueur { class Case {
Case * estDans;
char * nom ; // nom du joueur protected :
int capital; char * nom ;
public : int index;
Joueur(char * name, Case * deb) {
nom = strdup(name) ; public :
estDans = deb ; Case(char * name, int idx) {
capital = 150000; Nom = strdup(name) ;
} index = idx ;
}
char * getNom() { return nom; }
int getCapital() { return capital; } char * getNom() {
return nom;
Case * getCase() { return estDans ; } }
void setCase(Case * uneCase)
{ estDans = uneCase; } int getIndex() {
return index ;
void paye(int loyer){ }
capital -=loyer;
} } ; // ----- Case -----
void recoit(int loyer){
capital +=loyer;
}
void acheter(Terrain * t) {
if ( (! t->aUnProprietaire())
&& (capital >= t->getPrix()) ){
capital -= t->getPrix();
t->setProprietaire(this);
}
int lancement_D_Un_De() {
/** tirage aléatoire d’un dé */
srand(NULL) ;
return ((int)(random()*100)%6)+ 1;
}
int lancement_De_Deux_Des(){
/** resultat de lancement de 2 dés */
int result = lancement_D_Un_De() +
lancement_D_Un_De() ;
return result;
}
}; // ----- Joueur -----
Travail à faire
On se propose de comprendre, compléter, améliorer la modélisation UML
proposée par le développeur et de coder en partie le jeu avec le langage C++.
Pour cela, il s’agit de répondre directement sur les 2 formulaires qui vous ont
été distribués.
3/4 4/4
Partie n°1 : Modélisation UML (Analyse)
Question 1.1 (3 pt)
a) Le diagramme de classes proposé par le développeur est incomplet. Parmi les
manques nous signalons : (1) l’absence de cardinalités de quelques associations ;
(2) l’absence de précision des associations pouvant être promues en composition ou
agrégation. Complétez ces deux manques sur cette portion de diagramme de classes.
Remarque concernant les instances des classes ‘Case’(ou dérivées) et les instances de la classe
‘Groupe’ : Représentez que celles qui sont concernées par cette question.
b) Donnez l’ordre de navigation nécessaire pour savoir si un joueur donné est propriétaire de toutes
les propriétés du groupe d’un Terrain donné.
Joueur->Propriété->Groupe->(Propriété)*->Joueur
Partie 2 : Modélisation UML – Conception
Question 2.1 (1 pt)
Afin de faciliter l’implémentation des associations, on se propose de limiter au maximum possible la
navigation. Précisez le sens de navigation sur le diagramme de classes en bas de page (Q2.2).
Question 1.2 (2 pt) Question 2.2 (1 pt)
On suppose qu’on a deux joueurs. Le premier joueur s’appelle ‘Ali’. Il possède la gare du sud, la Pour comprendre les règles de gestion gouvernant l’évolution des liens entre les objets, on se propose de
gare du nord et la propriété Belleville. Il est actuellement à la compagnie des eaux. Le deuxième décorer les associations par les contraintes {ordered}, {addOnly}, {frozen}, {notUnique}. Décorez,
joueur s’appelle ‘Zied’. Il possède la compagnie d’électricité et d’eau. Il est actuellement à la case directement sur le diagramme de classes ci-dessous, chacune des associations par les contraintes de
départ. Conformément au diagramme de classes proposé par le développeur et à vos réponses à la gestion appropriées. Vous pouvez tout simplement annoter le bout navigable de chaque association par
question 1.1, représentez le diagramme d’objets qui illustre cette situation du jeu Monopoly. les symboles O,A,F,N (respectivement pour (O)rdered, (A)ddOnly, (F)rozen et (N)otUnique).
5/4
2/8
void ajouterCase(Terrain * ptrUnTerrain){
lesTerrains.push_back(ptrUnTerrain);
}
string getNom(){
return (nom);
}
} ;
Question 3.2 (4 pt) : La classe ‘Terrain’
On se propose d’implémenter la classe ‘Terrain’ ainsi que ses classes dérivées.
a) Rappelez les déclarations et les significations respectives d’une méthode virtuelle simple et d’une
méthode virtuelle pure (abstraite) en C++.
Méthode virtuelle simple :
Liaison dynamique permise avec les classes dérivées lors du polymorphisme ; Ajouter à la déclaration le
Partie n°3 : Codage en C++ conformément aux modifications UML que vous avez apportées préfixe : virtual
Question 3.1 (3 pt) : La classe ‘Groupe’
Le loyer d’un terrain d’un groupe donné dépend de la possession du joueur d’autres terrains dans le
même groupe. Par conséquent, il est convenable de définir des méthodes dans la classe Groupe qui Méthode virtuelle pure (abstraite) :
permettent de se rendre compte de cette dépendance de possession. C'est une méthode qui n’a pas d’implémentation ; Ajouter à la fin de déclaration : =0 ;
a) Indiquez toutes ces dépendances. b) Pensez-vous que la méthode calculerLoyer() peut être soit virtuelle soit non virtuelle sans
-int nbTerrain() //nombre de propriétés (gares, propriétés, compagnie) aucun problème sur le développement du jeu en question. Justifiez brièvement votre réponse.
- bool uniqueProprietaire (joueur *)// pour chaque propriété vérifier si le joueur possède tous les terrains Afin de permettre l'utilisation des objets de façon appropriée, calculerLoyer()doit être virtuelle
de ce groupe c) Le développeur pense que la méthode calculerLoyer() peut être soit virtuelle simple soit
b) Donnez, en C++, l’interface et l’implémentation de classe Groupe. virtuelle pure sans aucun problème sur le développement du jeu en question. Pensez-vous que le
class Groupe { développeur a raison. Justifiez brièvement votre réponse.
string nom;
Vector<Terrain *> lesTerrains; Pas de règle de calcul pour le cas d'un terrain ; le calcul est spécifique pour chaque type de
Public:
Groupe(string nom) : nom(nom){}
terrain=> méthode virtuelle pure (abstraite)
int nbTerrain(Joueur * j){
int compteur=0;
for (int i=0; i<lesTerrains.size();i++){ d) Donnez, en C++, l’interface de la classe Terrain. Principalement, il s’agit de donner, conformément
if( lesTerrains[i].getProprietaire()== j )
compteur++;
à vos réponses aux questions précédentes, (1) le constructeur, (2) la déclaration de tous les attributs
} nécessaires à l’implémentation des associations de cette classe ainsi que (3) les méthodes de
return (compteur); navigation nécessaires.
} class Terrain : public Case {
public:
bool uniqueProprietaire(Joueur * j){ Terrain(): prix(0),loyer(0){}
return( nbTerrain(j)== lesTerrains.size() ); Virtual ~ Terrain(){}
} Virtual bool aUnProprietaire(){ return false;}
3/8 4/8
Virtual int CalculerLoyer=0; a) Indiquez l’attribut que vous comptez utiliser pour l’implémentation de l’association Plateau-
Joueur getPropriétaire(){return propriétaire;} Case. Justifiez brièvement votre choix.
Void setPropriétaire(Joueur * s){propriétaire=s;}
Groupe getGroupe(){return groupe;} Plateau-Case : Collection indexée /collectrion triée//on se propose dans le cas le plus simple d'un
Protected: tableau statique de 40 cases.
int prix; Case cases[40]
int loyer;
Groupe * groupe;
b) La méthode init() de la classe plateau a pour rôle de construire les cases à partir du fichier
Joueur * Propriétaire;}; « cases.txt ». Donnez le corps de cette méthode.
e) Donnez, en C++, l’implémentation de la méthode ‘calculerLoyer()’ pour la classe ‘Terrain’ void Plateau::init() {
ainsi que l’implémentation de cette méthode pour chacune de ses 3 classes dérivées (‘Propriété’, ifstream fich("cases.txt"),
‘Gare’, ‘Compagnie’). if (fich){
int Propriété::calculerLoyer(){if (groupe->tout_prop(this, propriétaire)) return (2* loyer); else int nb_ligne;
return loyer; } fich>>nb_ligne;
int Gare::calculerLoyer(){return (groupe->nbre_gare()*loyer)} string type, nom, groupe;
int Compagnie::calculerLoyer(){if (nbre_compagnies(propriétaire)==2) return (4*loyer* int prix, loyer, numero;
propriétaire ->lancement_de_deux_des()); else return(loyer * propriétaire-> for (int i=0; i<nb_ligne;i++) {
lancement_de_deux_des());} fich >> type; cases[i].setType(type);
fich >> nom; cases[i].setNom(nom);
Question 3.3 (2 pt) : L’association ‘Jeu’-‘Joueur’
fich>>prix;
On choisit d’implémenter l’association multiple entre la classe ‘Jeu’ et la classe ‘Joueur’ par un vecteur
fich>>loyer;
STL comme suit : « vector<Joueur> joueurs ; ».
fich>>numero; cases[i].setIndex(numero);
a) Cette déclaration nécessite-t-elle une révision des méthodes de la classe Joueur. Expliquez fich>>groupe;
brièvement votre réponse.
}
} fich.close();
Oui, il faut vérifier que la classe Joueur ait obligatoirement un constructeur de copie, un else
opérateur d'affectation (operator =); possiblement un test d'égalité (operator ==) et un critère de cout<< "impossible d'ouvrir le fichier<<endl;}
tri(operator <).
Question 3.5 (2 pt) : La méthode jouer de la classe Jeu
La méthode jouerSonTour de la classe jeu assure une seule progression du joueur qui a le tour de
b) On se propose d’implémenter la méthode de la classe ‘Jeu’ qui retire un joueur du jeu et qui
rôle. Donnez le corps de cette méthode.
retourne vrai en cas de succès. Sachant qu’on ne souhaite pas utiliser les itérations (boucles for ou
while), donnez le code nécessaire pour implémenter cette méthode. void Jeu ::jouerSonTour() {
// On suppose pour cette question l’existence d’un objet dynamique joueurCourant qui pointe sur le joueur qui a le tour de rôle
bool Jeu:: retirerJoueur(char * nom) { int saut;
vector<Joueur>::iterator pos= find (joueurs. begin(), joueurs. saut=joueurcourant->lancement_de_deux_des();
end(),Joueur(nom)); int nv_pos=joueurcourant->estdans->index+saut;
if (pos!= joueurs.end()) { if nv_pos<=40;
erase (pos); return true;
else nv_pos= nv_pos-40;
}
else return false; } //On suppose que nom est le nom de la case d'index nv_pos;
Case * dest=Case(nom, nv_pos);
Question 3.4 (2 pt) : Initialisation du plateau joueurCourant->setcase(dest);
5/8 6/8
if (strcmp( des->type, "Passage");
else
{if (des->!aUnPropriétaire()) acheter(dest);
Else if( dest->getPropriétaire() != JoueurCourant->nom)
JoueurCourant->paye(dest->calculerLoyer);
}}
7/8

Vous aimerez peut-être aussi