Vous êtes sur la page 1sur 9

UNIVERSITE DE LA MANOUBA ANNEE UNIVERSITAIRE

-----¤¤¤¤----- 2007-2008
ECOLE NATIONALE DES SCIENCES
DE L'INFORMATIQUE

Devoir surveillé
Matière : Conception et Programmation orientées objets Date : samedi 24 novembre 2007
Niveau : II2 Durée: 2H
Enseignants : Y. JAMOUSSI, I. BEN HAMOUDA, R. CHEBIL, L. KETARI Documents : non autorisés

Problème
L’objectif de ce problème est de développer une application permettant de faire calculer à des
robots des itinéraires dans différentes zones géographiques. Un robot calcule un itinéraire lors de
son déplacement dans une zone géographique. Chaque zone géographique dispose d’un certain
nombre d’obstacles dont le nombre et la position de chaque obstacle sont connus à l’avance et fixes.
Robot dans la case de départ Case cible

Dans le cadre de ce problème, une zone géographique est une


grille de forme rectangulaire dont la taille est de NxM cases. P z
Au départ, le robot est situé sur une case désignée par case de
départ. Le robot calcule un itinéraire formé d’une succession z z
z
de cases qu’il peut visiter pour se rendre à une case de la
grille désignée par case d’arrivée. Il convient de mentionner

z z
qu’une case peut être visitée plus qu’une fois. Un itinéraire
peut être construit que lorsqu’on connaît les cases de départ
et d’arrivée qui restent inchangées. On suppose que les robots
se déplacent dans l’une des quatre cases voisines à la sienne z
(haut, bas, gauche, droite) à condition qu’elle ne soit pas un
obstacle (cercle noirci).
La figure à droite représente une zone géographique composée de sept obstacles avec un robot (nommé
Zulu) initialement dans une case de départ devant se rendre à une case cible (quadrillée).
Dans un premier temps, on se propose d’utiliser uniquement les 4 classes : Grille, Robot, Case
et Itineraire. Un développeur a réalisé le modèle de conception UML incomplet suivant :

Travail à faire
On se propose de comprendre et compléter la modélisation UML proposée par le développeur,
de coder en partie l’application avec le langage C++ et d’améliorer la modélisation UML. Pour
cela, il s’agit de répondre directement sur les deux formulaires qui vous ont été distribués.
20  Nom : …….….................. Prénom :……………………Classe :……….

Partie 1 : Modélisation UML


Question 1.1 (0,75+1,25 pts)
a) Vous remarquez l'utilisation d'un type particulier d'association dans le diagramme de classes
proposé par le développeur. Lequel ? Rappelez sa définition.
Æ : association unidirectionnelle = navigation dans un seul sens

*on tolère ceux qui ont traité correctement la dépendance - -> (bien que bizarre !)

b) Commentez la signification de chaque association dans le diagramme proposé par le


développeur.
Grille-Robot (habitant) : une grille peut contenir 0 ou plusieurs habitant de type robot

Grille-Case (Obstacle) : une grille contient 0 ou plusieurs obstacles de type case

Itineraire-Case (départ) : un itinéraire à 1 et une seule case de départ

Itineraire-Case (arrivée) : un itinéraire à 1 et une seule case d’arrivée

Itineraire-Case (chemin) : un itinéraire est formé par à 0 ou plusieurs cases visitées formant ainsi un
chemin

Question 1.2 (2 pts)


Elaborez le diagramme d’objets représentant la zone géographique présentée dans la première
figure (avec 1 zone géographique, 7 obstacles, un robot). Prenez les conventions suivantes : la
position 0,0 correspond au coin haut gauche de la grille, les colonnes positives à droite, les
lignes positives en bas.
Question 1.3 (0,5 + 0,5 pts)
De petites modifications s’avèrent nécessaires pour que la classe Robot puisse réaliser le
traitement de la méthode « atteindrePosition » assurant le calcul d’un itinéraire. Voici un
exemple de modification qu’il est possible d’apporter à la classe Robot :
1. Ajouter un attribut nommé zoneDuRobot dont le type est un pointeur sur la Grille
2. Ajouter l’opération presenceObstacle qui retourne vrai en cas d’existence d’obstacle à la
position (x,y)

a) Reflétez cette modification sur le modèle UML en représentant que les classes concernées par le
changement.
class Class Model

Robot

Grille - posColonne: int


+zoneDuRobot +Habitant - posLigne: int
- nbColonnes: int
- nbLignes: int 0..1 * - zoneDuRobot: Grille*

+ atteindrePosition(Case) : Itineraire
+ presenceObstacle(int, int) : boolean

b) Une instance de la classe Itineraire peut-elle reconnaître les obstacles ? Justifier votre
réponse.
Non, car à partir d’une instance itinéraire on ne peut naviguer que vers : case départ, case
d’arrivée et les cases visitées par le robot.

Rq : A partir de case on n’a pas de visibilité sur les obstacles. La seule classe qui a une
visibilité sur les obstacles est la classe Grille ou toutes celles qui peuvent naviguer
vers grille (soit Robot).

Question 1.4 (1+1,5 pts)


Pour la compréhension de l’évolution du modèle objet, on se propose de décorer les associations par
les contraintes de gestion : frozen, addOnly, ordered, notUnique.
a) Rappelez la signification de chacune de ces contraintes.
frozen : le tissage des liens est fixé lors de la création et ne peut pas changer.

addOnly : Il est possible de tisser de nouveaux lien mais impossible d’en supprimer

ordered : les éléments de la collection représentant le tissage des liens sont ordonnés

notUnique : Il est possible d’avoir plus qu’un lien entre deux objets avec la même association
b) Décorez chaque association par le ou les contraintes de gestion appropriées. Il est conseillé de
donner une réponse textuelle : le ou les contraintes par association (une ligne par association).
Grille-Robot (habitant) :
Grille-Case (Obstacle) : frozen,
Itineraire-Case (départ) : frozen
Itineraire-Case (arrivée) : frozen
Itineraire-Case (chemin) : notUnique, addOnly, ordered

Partie 2 : Codage C++


Question 2.1 (1 + 1,5 pt)
a) Discutez brièvement l’impact des contraintes de gestion des associations dégagées dans la
question précédente (1.4-b) sur le codage C++ de l’application en question.
Frozen : l’initialisation doit se faire au niveau du constructeur

notUnique : prévoir un moyen pour distinguer 2 liens sur un même objet (par exemple en
duplicant les objets !)

addOnly : prévoir au niveau des méthodes l’ajout et/ou l’insertion (add) pas de suppression

ordered : prévoir un ordre (soit par chainage entre les éléments ou par un index sur
l’élément

pas de contraintes : il faut prévoir toutes les méthodes (add, insert , remove,
removeAll, etc.)

b) L’implémentation des associations avec cardinalité multiple nécessite l’utilisation d’une


structure qui implémente une collection (non définie dans le modèle UML proposé par le
développeur). Quelle structure vous comptez utiliser pour les différentes associations multiples,
sachant qu’on vous demande de choisir uniquement parmi les quatre structures suivantes : un
tableau, un tableau dynamique, une liste simplement chaînée, et une liste doublement chaînée.
Justifiez votre choix.
Grille-Robot (habitant) : Aucune contrainte n’est indiquée dans l’énoncé. Donc on a
besoin d’une collection dont la taille n’est pas connue à priori => liste simplement ou
doublement chaînée. Aucune contrainte sur l’ordre entre les habitants => on peut choisir
liste simplement chaînée

Grille-Case (Obstacle) : on a besoin d’une collection dont la taille n’est pas une constante
indépendante de la grille et donc on écarte l’utilisation d’un tableau statique. Mais la taille
de la collection est une valeur connue lors de la construction de la grille => on peut opter
pour un tableau dynamique. Mais comme la grille ne connaît pas le nombre d’obstacles =>
plus propice d’utiliser une liste simplement chaînée.

Itineraire-Case (chemin) : on a besoin d’une collection dont la taille n’est pas connue à
priori. L’ordre sert uniquement pour former une succession de cases. On n’a pas besoins
d’opération qui exploite le double chainage => liste simplement chainée
Question 2.2 (2,5 pts)
Sachant qu’on ne veut apporter aucune modification sur le nombre d’associations impliquées avec
la classe Case, donnez la déclaration et l’implémentation de la classe Itineraire. Il est conseillé de
donner l’implémentation de toutes les méthodes avec leur déclaration.
struct EltList{
Case *t;
EltList *next;
};

class Itineraire
{
private:
Case *depart; //on accepte aussi Case depart (sans pointeur)
Case *arrivee; //on accepte aussi Case arrivee
Eltlist *chemin;
public :
Itineraire(Case *dep, Case *arr) :
depart(dep), arrivee(arr), chemin(NULL) {}

Case *getDepart() const {return depart;}

Case *getArrivee() const {return arrivee;}

EltList *getChemin() const {return chemin;}

void addChemin(Case *nvelleCase) {


EltList *nvelle;

nvelle=new EltListe;

nvelle->t=nvelleCase;
nvelle->next=NULL;

if (!chemin )
chemin=nvelle;
else
{
EltList * tmp;
for(tmp=chemin; tmp->next!=NULL; tmp=tmp->next);
tmp->next=nvelle;
}
}

~Itineraire(){
while (chemin != NULL) {
EltList * tmp;
tmp = chemin;
chemin = chemin->next;
delete tmp;
}
delete depart ; // tt depend de leur usage
delete arrivee ; // tt depend de leur usage
}
};
Nom : ………….................. Prénom :……………………… Classe :……….

Question 2.3 ( 0,5+2 pts)


a) On suppose que chaque zone géographique est décrite dans un fichier d’entiers structuré comme
suit : un premier couple informe sur le nombre de colonnes et le nombre de lignes, un entier qui
informe sur le nombre d’obstacles et une suite de couples (colonne, ligne) représentant la
position des obstacles. Donnez le contenu de ce fichier pour la zone géographique de l’énoncé
en utilisant la convention de la question 1.2.

7 6 7 1 4 2 0 2 1 3 1 3 3 4 3 5 2

b) Donnez la déclaration et l’implémentation de la classe Grille sachant que la construction de la


grille se fait à partir d’un nom de fichier ayant la structure susmentionné. Il est conseillé de
donner l’implémentation de toutes les méthodes avec leur déclaration.

struct EltHabitant{ ~Grille () {


Robot *habitant; EltObstacle * tmp ;
EltHabitant *next; while (obstacles != NULL) {
}; tmp = obstacles ;
obstacles=obstacles->next ;
struct EltObstacle{ delete tmp;
Case *Obstacle; }
EltObstacle *next;
}; // destruction des habitants
// de la classe App
class Grille{ }
private:
int nbColonnes; EltHabitant *getHabitant() const
int nbLignes; {return habitants;}
EltHabitant *habitants;
EltObstacle *obstacles;
public: void setHabitant(Robot *R){
Grille(char * nomFichier){ EltHabitant *nvelle;
int nbObstacle; nvelle=new EltHabitant;
ifstream f(nomFichier); nvelle->habitant=R;
f>>nbColonnes; nvelle->next=habitants;
f>>nbLignes; habitants = nvelle ;
f>>nbObstacle; }

Case *getObstacle() const {


habitants = NULL ; return obstacles;}
obstacles = NULL ;

while (nbObstacle--) { };
EltObstacle * nv ;
nv = new EltHabitant ;
f >> x >> y ;
nv->Obstacle=new Case(x,y);
nv->next = obstacles ;
Obstacles = nv ;
}
}
Question 2.4 (1+1 pts)
a) Donnez l’implémentation de l’opération bool presenceObstacle(int x,int y) qui,
pour une case se trouvant à la ligne x et la colonne y, retourne vrai si cette case est un obstacle
et faux sinon. (N’oubliez pas de respectez vos réponses aux questions précédentes)
bool Robot::presenceObstacle(int x, int y) {
Grille *g=getZoneRobot() ;
EltObstacle * obs = g->getObstacle();
while (obs) {
if ((obs->Obstacle.getLigne()==x)
&& (obs->Obstacle.getColonne()==y) )
return TRUE;
}
return FALSE;
}
b) On suppose que la classe Robot à une méthode intelligente prochaineCaseAVisiter()
(non mentionnée dans le diagramme de l’énoncé) qui lors du déplacement du robot d’une case à
une autre l’aide à s’orienter vers la cible. Cette méthode retourne un sens de déplacement {haut,
bas, gauche, droite} sans tenir compte des obstacles, mais heureusement elle est indéterministe.
Aussi, on suppose que le robot abandonne la recherche et retourne NULL s’il fait un nombre de
déplacement supérieur à 2 fois la taille de la grille et qu’il ne retrouve pas la cible. Donnez
l’implémentation de l’opération atteindrePosition.

enum sens {haut, bas, gauche, droite} ;


Itineraire* Robot::atteindrePosition (Case * cible) {

int count = 2 * zoneDuRobot->getTaille() ;


Itineraire * it = new Itineraire( new Case(posLigne,posColonne), cible);

while((posLigne != cible->getLigne()) && (posColonne != cible->getColonne())


&& (--count != 0) ) {
int dlig=0; int dcol=0 ;
switch ( prochaineCaseAVisiter() ) {
case haut : dlig=-1; break;
case bas : dlig=+1; break;
case droite : dcol=+1;
case gauche : dcol =-1;
}

if ( ! presenceObstacle(posLigne+dlig,posColonne+dcol)) {
posLigne+=dlig ; posColonne+=dcol ;
// deplacement effectif du robot
It->add( new Case(posLigne, posColonne) ) ;
}
}

if ( count !=0 ) return it; else { delete it ; return NULL ; }

}
Partie 3 : Amélioration de la modélisation UML

Question 3.1 (1 pt)


On rappelle que dans la question 1.3, on a rajouté l’opération presenceObstacle dans la classe
Robot. Est-il possible de déplacer cette opération dans une autre classe ? Justifiez votre réponse.

Oui il est possible de déplacer l’opération « presenceObstacle » dans une autre classe car la classe
responsable est la classe Grille. C’est elle qui contient toutes les informations pour pouvoir réaliser
le traitement.

Question 3.2 (2 pts)


On veut savoir s’il est possible de mémoriser les itinéraires suivis par chaque Robot.
Est-il possible de le faire avec l’association «habitant» entre les classes Grille et Robot et/ou une
autre association de la solution actuelle ? Justifiez votre réponse ?

Avec la solution actuelle, par l’association « habitant » entre les classes Grille/Robot il n’est pas
possible de mémoriser les itinéraires suivis par chaque robot.

Il s’agit de démontrer que toutes les navigations ne permettent pas de joindre le robot avec
l’itinéraire. D’ailleurs, ce dernier est transmis par un return dans une méthode de Robot.

Toutefois, on peut le faire avec plusieurs façons. Voici à titre d’exemple 1 façon :
Ajouter une association entre Robot et Itinéraire [1-*] (Robot se déplace plusieurs fois pour calculer
itinéraire). Plus il faut que l’itinéraire soit relatif à une grille Æ rendre Grille une classe associative
de la nouvelle association.
Question 3.3 (2 pts)
On se propose d’ajouter la classe Application qui joue le rôle d’interface entre le programme
principal et les constituants du problème en question (Grille, Robot, Case, Itineraire). A cet effet, on
se propose aussi de transformer toutes les associations dans le diagramme de classes réalisé par le
développeur en introduisant, si c’est possible, un maximum d’association de type composition ou à
la limite des associations de type agrégation. Rappelez la définition de ces deux concepts et donnez
une proposition d’un nouveau diagramme de classes incluant la classe Application.
L’agréation est un cas particulier d’association qui représente une relation d’inclusion structurelle
ou comportementale d’un élément (agrégé) dans un ensemble (agrégat). La durée d vie des agrégés
est indépendante de celle de l’agrégat. Il est possible de rattacher les agrégés à plus d’un agrégat. La
composition est un cas particulier d’association avec des contraintes décrivant la notion de
composant (contenance structurelle). Les contraintes liées à la composition sont les suivantes :

- Un objet composant ne peut être que dans un seul objet composite.


- Un objet composant n’existe pas sans son objet composite.
- Si un objet composite est détruit, ses composants aussi.

Grille  Application 
1  Interface

Habitant 
Robot

Obstacle 

Départ
1
Case  Itinéraire 

*  Chemin

1
Arrivée

Vous aimerez peut-être aussi