Simulation d`un robot aspirateur chargé de nettoyer une pièce

Transcription

Simulation d`un robot aspirateur chargé de nettoyer une pièce
L2 Informatique
Université de Bourgogne
2011-2012
Projet :
Simulation d’un robot aspirateur chargé de
nettoyer une pièce comportant des obstacles.
Algorithmique et programmation avancée
Rapport pré-final rédigé en LATEX
PONCIANO Jean-Jacques
PRUDHOMME Claire
Sommaire
1
Introduction
3
2
Analyse
4
2.1
Architecture : Héritage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
2.2
Détail des classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
2.2.1
Classe « Menage » . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
2.2.2
Classe « Piece » . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
2.2.3
Classe « PieceException » . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
2.2.4
Classe abstraite « Robot » . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
2.2.5
Classe « RI » héritée de « Robot » . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
2.2.6
Classe « RII » héritée de « Robot » . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
2.2.7
Classe « RIII » héritée de « Robot » . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
2.2.8
Classe « Coordonnee » . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
3
Développement
15
3.1
Arborescence des packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
3.2
Algorithmes utilisés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
3.2.1
Déplacement aléatoire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
3.2.2
Les fourmis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22
3.2.3
Déplacement du Robot de type III . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
24
3.2.4
Création de pièces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
3.2.5
Algorithme de correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
3.2.6
Algorithme de « contamination » . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
Interface graphique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
30
3.3
4
Statistiques
32
4.1
Conception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
4.2
Exploitation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
4.2.1
Vision globale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
4.2.2
Statistiques en fonction des dimensions des pièces . . . . . . . . . . . . . . . . . . . .
34
4.2.3
Statistiques en fonction du pourcentage d’obstacles des pièces . . . . . . . . . . . . .
35
5
Validation
37
6
Exploitation
38
1
7
Conclusion
47
8
Annexe
48
2
1
A
Introduction
l’heure où le monde continue son ascension vers la robotique, l’aspirateur manuel se voit concurrencé
par des robots aspirateurs autonomes. Néanmoins l’adaptation dans la vie courante des robots
aspirateur stagne un peu. Les causes principales sont le coup élevé d’un robot mais également la rapidité
du robot pour effectuer un nettoyage complet d’une pièce. En effet, la grande majorité des robots effectuent
un déplacement aléatoire. C’est pourquoi, beaucoup de personnes doutent de leur efficacité et préfèrent la
méthode traditionnelle, plus contraignante mais néanmoins efficace. Ce projet ayant pour but la création
d’un programme de simulation du fonctionnement d’un robot chargé de faire le ménage dans une pièce,
nous a permis d’étudier les différentes méthodes permettant de concevoir le déplacement d’un robot.
Cette démarche d’étude a aboutit à la construction de trois types de robots différents. Le premier, n’ayant
aucune mémoire, a été élaboré à l’image des robots existants, c’est-à-dire avec un déplacement aléatoire.
Les deux autres types de robots possèdent une mémoire. Celui du deuxième type, avec une mémoire
limitée, se rapproche des robots haut de gamme actuels alors que celui du troisième type utilise une
mémoire utopique, celle-ci étant infini. Cette étude fut très intéressante car elle a permis de réfléchir sur
l’évolution possible des robots mais plus particulièrement de comparer différentes façons de nettoyer une
pièce contenant des obstacles et ainsi d’étudier la rentabilité des robots en fonction de leur mémoire. Et
l’on peut alors se demander s’il existe une différence transcendante entre ces trois grandes catégories de
robots : les robots sans mémoire, les robots à mémoire limitée, et les robots idéaux ? Pour essayer d’y
répondre nous avons conçu un programme de simulation du fonctionnement d’un robot aspirateur. En
premier lieu, une analyse a été élaboré pour répondre du mieux possible au cahier des charges demandé.
Pour ce faire, nous avons réalisé l’architecture de notre programme puis développé les points les plus
importants de celle-ci dans le soucis d’optimiser au mieux la possibilité d’adaptation du programme, en
exploitant les capacités de la programmation objet en langage Java. Puis nous avons élaboré les algorithmes
permettant le déplacement de chaque type de robots. Enfin, nous avons réalisé une interface graphique
entre l’utilisateur et le programme dans le but d’obtenir une meilleure visualisation de l’étude.
3
2
Analyse
2.1
L
Architecture : Héritage
a construction du programme a été effectuée après une étude approfondie du cahier des charges. Pour
ce il faut commencer par une analyse des besoins et des spécificités du programme. Grâce à la mo-
délisation objet du langage Java, on commence par modéliser les trois types de robots en cherchant leurs
attributs et leurs méthodes en fonction de leurs nécessités, puis il faut modéliser ce qui est indispensable
pour une séance de ménage telle qu’une pièce ou les coordonnées du robot. Dans un second temps, il faut
réfléchir à la partie visuelle : réfléchir aux fonctionnalités qui peuvent être utiles à l’utilisateur ou encore
réfléchir à la disposition des éléments d’une fenêtre pour que ce soit le plus pratique et le plus joli possible. Après avoir esquissé le squelette du programme, il faut le mettre en forme et coder les algorithmes
sur lesquels il repose.
’est ainsi que le programme a aboutit à l’architecture ci-dessous. On peut remarquer qu’elle est centrée
C
autour d’un noyau (en bleu turquoise) qui constitue le c ?ur du programme, c’est dans celui-ci que
toutes les opérations primordiales sont effectuées.
4
Figure 2.1 – Structure du programme
Figure 2.2 – Legende de la structure du programme
5
2.2
Détail des classes
Dans cette partie, nous allons présenter plus en détail le c ?ur du programme.
Dans un premier temps, le diagramme ci-dessous présente son architecture, puis, dans un deuxième
temps, chaque élément le constituant sera expliqué.
Figure 2.3 – Les packages
Figure 2.4 – Les packages
6
2.2.1
Classe « Menage »
Figure 2.5 – Structure de la classe « Menage »
« Menage » effectue le ménage, c’est à dire qu’elle coordonne chaque classe entre elle. Par conséquent
elle contient les Robots, dont un robot courant robot, une piece, un temps maximum pour l’exécution du
ménage ainsi qu’une échelle de temps en millisecondes. L’unique procédure est menageR qui effectue le
déplacement du robot dans la pièce et stocke chacun de ses déplacements dans une liste chainée coord
jusqu’à ce que la pièce soit propre ou que le temps imparti soit écoulé.
La deuxième procédure est la création d’une pièce dans un fichier texte de manière aléatoire par l’utilisation de l’algorithme de création de pièces.
7
2.2.2
Classe « Piece »
Figure 2.6 – Structure de la classe « Piece »
Cette classe représente la pièce à nettoyer, elle contient une matrice binaire à deux dimensions, piece, matérialisant la pièce, le nombre de lignes et de colonnes de cette matrice, ainsi qu’une autre matrice binaire
à deux dimensions, avancement permettant de suivre l’avancement du ménage effectué en remplaçant la
valeur des cases par lesquelles un robot est passé par la valeur représentant les obstacles (1), sachant
qu’elle fut créée à l’identique de la matrice piece. Cette dernière matrice évolue grâce à l’utilisation de la
procédureavancer.
Elle contient aussi plusieurs méthodes, telles que piecePropre renvoyant un boolean indiquant l’état de la
pièce, pour ce il vérifie que la matrice avancement ne possède plus aucune valeur 0, et traduction, qui permet
de créer la matrice piece à partir d’un fichier texte choisi au préalable, et une méthode toStringpermettant
l’affichage de la matrice piece. Elle possède aussi des fonctions permettant la correction, si besoin, de
pièces. Nous y reviendrons lors du développement.
8
2.2.3
Classe « PieceException »
Figure 2.7 – Structure de la classe « PieceException »
Cette classe permet de gérer les exceptions liées aux pièces et de signaler l’exception en récupérant un
message spécifique lié à la cause de l’exception générée.
2.2.4
Classe abstraite « Robot »
Figure 2.8 – Structure de la classe « Robot »
Robot est une classe abstraite qui contient les attributs communs aux trois robots, c’est à dire leurs coordonnées ainsi que leur fonction de déplacement, cette dernière étant abstraite car différente pour chacun
des Robots.
9
2.2.5
Classe « RI » héritée de « Robot »
Figure 2.9 – Structure de la classe « RI »
RI utilise l’algorithme de déplacement aléatoire que l’on verra plus en détail dans la partie développement,
utilisé comme stratégie de déplacement. Etant dépourvu de mémoire, seule une telle stratégie semble
pouvoir nettoyer entièrement la pièce, certes avec un temps assez conséquent et surtout, non constant.
10
2.2.6
Classe « RII » héritée de « Robot »
Figure 2.10 – Structure de la classe « RII »
RII utilise trois stratégies utilisant toutes trois L’algorithme des fourmis, que l’on verra plus en détail dans
le développement. L’utilisation de cet algorithme est possible grâce à une mémoire limité sous forme de
liste chainée ayant une taille maximum définie et modifiable.
Première stratégie :
Lors du choix entre plusieurs cases de même statut( plusieurs cases lavées récem-
ment ou non lavées), elle choisira de manière aléatoire le déplacement parmi les possibilités de déplacement de même valeur (plusieurs cases sales ou plusieurs cases propres sans cases sales).
Deuxième stratégie :
Fortement semblable à la première stratégie, elle diffère néanmoins de l’autre
par un choix de déplacement qui ne se fait plus de manière aléatoire, mais en privilégiant le schéma
« Droite,Haut,Gauche,Bas ». C’est-à-dire, si le robot peut, il cherchera toujours à aller à droite sans revenir
sur ses pas, sinon il cherchera à aller en haut, sinon à gauche et sinon en bas.
11
Troisième stratégie :
C’est sa mémoire limitée à une liste chainée de taille maximum définie qui permet
l’utilisation de cette stratégie. Celle-ci est intéressante uniquement si on permet au Robot d’avoir une taille
mémoire correcte supérieure au périmètre de la pièce. En effet, cette stratégie répète le même schéma que
précédemment, mais au lieu de chercher à aller tout le temps à droite, et sinon en haut etc... elle s’appuie
sur des rotations plutôt que des changements.
C’est-à-dire, lorsque le robot rencontre un obstacle, il effectue une rotation sur lui même dans le sens
positif ce qui a pour conséquence d’échanger la droite avec le haut, le haut avec la gauche, la gauche
avec le bas, et le bas avec la droite, et ce uniquement si la case en dessous de lui est un obstacle. Dans le
cas contraire, lorsqu’il n’aura plus d’obstacle en dessous de lui, celui-ci effectuera une rotation négative
(l’inverse de la rotation positive), permettant alors au robot de longer l’obstacle.
Cette méthode possède néanmoins l’inconvénient de faire tourner le robot tout autour des contours de la
pièce en repassant continuellement sur ses pas, si sa mémoire s’avère trop petite. Dans le cas contraire,
c’est-à-dire si sa mémoire est suffisante, il privilégiera toujours la case sale aux autres en essayant de ne
revenir sur ses pas que si nécessaire, ce qui lui permet de nettoyer convenablement la pièce.
La limitation de la mémoire à une seule liste ne nous a pas permis de concevoir correctement ni une
recherche de case sale dans la mémoire du robot, ni un algorithme de recherche du plus court chemin
entre lui et une case sale. Il cherchera alors de manière empirique une case sale en repassant sur ses cases
les plus anciennes dans sa mémoire.
12
2.2.7
Classe « RIII » héritée de « Robot »
Figure 2.11 – Structure de la classe « RIII »
Les tests effectués avec un robot de type II ont permis de se concentrer sur une stratégie qui nous semblait
très pertinente, c’est pourquoi RIII n’utilise qu’une seule stratégie, dont son fonctionnement est semblable
à la troisième stratégie de RII. Cependant, puisque sa taille est illimitée, son efficacité est très élevée
lorsqu’il est en présence de cases sales ou d’obstacles. En effet, celui-ci va, tel qu’un enfant colorierait une
image en repassant ses contours intérieurs sans repasser sur ses propres lignes et en se rapprochant à
chaque passage du centre du dessin, nettoyer la pièce en repassant uniquement si nécessaire sur ses pas.
De plus, nous avons pu élaborer un algorithme de recherche de case sale à partir des données enregistrées
par le robot sur les cases qu’il a pu rencontrer. Ces données que nous combinons à un algorithme de
recherche du plus court chemin, permettent au robot de ne pas perdre, ni son chemin, ni son temps
lorsqu’il n’a plus de case sale autour de lui. Pour cela, entre deux cases situées à égale distance, il privilégie
la case optimisant le plus l’utilisation du schéma de déplacement. Nous reviendrons plus en détail sur les
algorithmes dans le développement.
13
2.2.8
Classe « Coordonnee »
Figure 2.12 – Structure de la classe « Coordonnee »
Cette classe contient les coordonnées x et y d’une case, c’est sur elle que s’appuie l’utilisation des robots,
de la pièce ou encore de l’interface graphique.
14
3
L
Développement
’analyse a permis de construire le squelette, l’ossature du programme mais c’est grâce au développe-
3.1
ment que nous construisons son contenu.
Arborescence des packages
Ce contenu a été réparti en cinq packages pour plus de lisibilité, de compréhension, et d’organisation mais
aussi afin de faciliter une réutilisation ou une extension éventuelle de notre programme. La séparation par
modules permet au programme d’être évolutif et plus facile à maintenir.
Figure 3.1 – Les packages
Chaque classe fut triée selon ses fonctionnalités et son utilisation ce qui a pour but de rendre le programme
le plus adaptable possible. En effet, nous pouvons implémenter une autre interface graphique simplement
en remplaçant le package Interface Graphique par le nouveau et en réutilisant les autres classes des
packages. Ainsi si d’autres personnes souhaitaient apporter des modifications au programme d’origine,
elles n’auraient pas besoin de revenir modifier les classes existantes.
15
Le package Interface graphique regroupe toutes les fenêtres visuelles du programme (à part la fenêre permettant de visualiser les statistiques) ainsi que les classes ou encore les images utilisées par ces dernières.
Figure 3.2 – Le package Interface graphique
Le package robot contient les classes robots c’est-à-dire qu’il contient la classe abstraite robot et les trois
classes correspondant aux trois types de robot : RI, RII, RIII.
Figure 3.3 – Le package robot
Le package liste regroupe ce qui appartient à la famille des listes ou ce qu’elles utilisent tels que les
noeuds.
Figure 3.4 – Le package Liste
16
Le package Statistique regroupe tout ce qui concerne la réalisation de statistiques c’est-à-dire qu’elle
contient une classe statistique qui utilise des données d’où la présence de la classe Donnee mais elle
contient aussi la fenêtre permettant de visualiser les statistiques.
Figure 3.5 – Le package Statistique
Le package Outil regroupe la classe ménage ainsi que les classes dont elle a besoin et qui ne sont pas déjà
classées dans un autre package.
Figure 3.6 – Le package Outils
17
3.2
Algorithmes utilisés
3.2.1
Déplacement aléatoire
Nous avons longuement cherché un algorithme pour le robot aspirateur de type 1 sans mémoire. Après
de nombreux essais, nous nous sommes rendus compte qu’un seul algorithme permettait le nettoyage
complet d’une pièce,celui d’un déplacement aléatoire, les autres finissant soit par faire boucler le robot
sur lui même, soit par oublier de laver une ou plusieurs cases.
Le fonctionnement de l’algorithme consiste à choisir une case aléatoirement et si celle-ci n’est pas envisageable, il en choisit une autre parmi celles restantes, et ce jusqu’à ce qu’il en trouve une qui soit accessible.
Pour cela, les 4 déplacements envisageables pour le robot sont caractérisés par un chiffre entre 0 et 3
inclus, puis placés dans un tableau. Ensuite, par un tirage aléatoire nous sélectionnons un déplacement et
regardons s’il est accessible ou pas. S’il l’est, le robot exécute le déplacement sélectionné, sinon il supprime
le déplacement testé et recommence la même opération sur les déplacements restants. L’utilisation de cet
algorithme nécessite une création de la pièce correcte, c’est-à-dire sans que le robot soit entouré, dés le
début, par des obstacles.
Un algorithme permettant de créer une pièce parfaite a été conçu, il est expliqué un peu plus loin.
De plus, cet algorithme de déplacement aléatoire constituera une base solide pour le développement du
deuxième robot. En effet nous l’avons réutilisé comme base stratégique de déplacement pour le robot de
deuxième type ; nous y reviendrons également. Algorithme de déplacement aléatoire :
1
2
// choix d’une première possibilité
d=entier correspondant à une direction
3
4
5
6
7
8
9
/∗ direction :
∗ si d=0:haut
∗ si d=1:bas
∗ si d=2:gauche
∗ si d=3: droite
∗/
10
11
12
13
Coordonnee co = coordonnées clonées du robot
x = abscisse des coordonnées actuels du robot
y = ordonnée des coordonnées actuels du robot
14
15
16
17
boolean passer = faux
tab = tableau d entier de taille 4
nb = 4
18
19
20
21
pour i de 0 à 3
tab[i] = i;
fin pour
22
23
24
25
26
27
28
// cas où le robot est entouré d obstacles au démarrage
si x = 1 et y = nombre de ligne de la pièce - 1
si la case (x, y - 1) = 1 et que la case (x + 1, y) = 1
une exception se lance et affiche "Accès à la pièce impossible"
fin si
fin si
29
30
31
// test un premier chemin
d=valeur aléatoire comprise entre 0 inclus et 4 exclus
32
33
si tab[d]=0
18
si la case (x, y - 1) != 1
ordonnée de co=y - 1
passer = vrai
fin si
34
35
36
37
38
fin si
39
40
41
42
43
44
45
si tab[d]=1
si la case (x, y + 1) != 1
ordonnée de co=y + 1
passer = vrai
fin si
fin si
46
47
48
49
50
51
52
si tab[d]=2
si la case (x - 1, y) != 1
abscisse de co=x - 1
passer = vrai
fin si
fin si
53
54
55
56
57
58
59
si tab[d]=3
si la case (x + 1, y) != 1
abscisse de co=x + 1
passer = vrai
fin si
fin si
60
61
62
63
64
65
66
// test un deuxième chemin si premier pas
si il est pas passer
nb=nb-1
pour i de d à nb-1
tab[i] = tab[i + 1];
fin pour
accessible
67
68
d=valeur aléatoire comprise entre 0 inclus et 3 exclus
69
70
71
72
73
74
75
si tab[d]=0
si la case (x, y - 1) != 1
ordonnée de co=y - 1
passer = vrai
fin si
fin si
76
77
78
79
80
81
82
si tab[d]=1
si la case (x, y + 1) != 1
ordonnée de co=y + 1
passer = vrai
fin si
fin si
83
84
85
86
87
88
89
90
91
92
93
si tab[d]=2
si la case (x - 1, y) != 1
abscisse de co=x - 1
passer = vrai
fin si
fin si
si tab[d]=3
si la case (x + 1, y) != 1
abscisse de co=x + 1
passer = vrai
19
fin si
94
95
fin si
96
97
98
99
100
101
102
// test un troisième chemin si les deux premiers sont
si il est pas passer
nb=nb-1
pour i de d à nb-1
tab[i] = tab[i + 1]
fin pour
inaccessibles
103
104
d=valeur aléatoire comprise entre 0 inclus et 2 exclus
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
si tab[d]=0
si la case (x, y - 1) !=
ordonnée de co=y - 1
passer = vrai
fin si
fin si
si tab[d]=1
si la case (x, y + 1) !=
ordonnée de co=y + 1
passer = vrai
fin si
fin si
si tab[d]=2
si la case (x - 1, y) !=
abscisse de co=x - 1
passer = vrai
fin si
fin si
si tab[d]=3
si la case (x + 1, y) !=
abscisse de co=x + 1
passer = vrai
fin si
fin si
1
1
1
1
131
132
133
134
135
136
137
138
139
// dernière possibilité
si il est pas passer
si d =1
d = 0
sinon
d = 1;
fin sinon
fin si
140
141
142
143
144
145
146
147
148
149
150
151
152
153
si tab[d]=0
si la case (x, y - 1) != 1
ordonnée de co=y - 1
passer = vrai
fin si
fin si
si tab[d]=1
si la case (x, y + 1) != 1
ordonnée de co=y + 1
passer = vrai
fin si
fin si
si tab[d]=2
20
si la case (x - 1, y) != 1
abscisse de co=x - 1
passer = vrai
fin si
154
155
156
157
158
159
160
161
162
163
164
fin si
si tab[d]=3
si la case (x + 1, y) != 1
abscisse de co=x + 1
passer = vrai
fin si
fin si
165
166
167
168
fin si
fin si
fin si
169
170
171
172
abscisse du robot = abscisse de co
ordonnée du robot = ordonnée de co
return co;
21
3.2.2
Les fourmis
Cet algorithme est ainsi nommé car il imite le mode de déplacement des fourmis, de leur fourmilière
jusqu’à un point de nourriture.En effet, lorsqu’une fourmi se déplace elle laisse derrière elle une trace de
son passage. Plus elle passe par un chemin plus il est marqué.
Nous avons donc attribué cette caractéristique à notre deuxième robot (le robot de type 2) dans la limite
de sa mémoire, afin que contrairement à une fourmi il évite de repasser sur les cases marquées (les
cases sur lesquelles il est déjà passé). Le fonctionnement de cet algorithme repose sur une liste chainée
« coo » qui représente sa mémoire, elle est donc d’une taille limitée. Tout d’abord, il commence par créer
quatre coordonnées correspondant à la prochaine case selon les quatre déplacements envisageables. Puis il
regarde celles qui ont déjà été visitées parmi celles qui sont accessibles. Pour cela il stocke dans un tableau
comme valeur, l’indice référençant la case qui a été visitée, dans la liste chainée (repérage du marquage).
Si elle n’a pas été lavée il renvoie la taille maximum de la liste. Ainsi les cases qui n’ont pas encore été
lavées ont une valeur plus élevée que les autres (valeur maximale). Ce qui permet par la suite de faire un
choix aléatoire parmi les cases qui n’ont pas été lavées ou si toutes l’ont été parmi celles-ci.
Algorithme des fourmis :
1
2
3
4
co = Coordonnées actuel du robot
x = abscisse des coordonnées actuels du robot
y = ordonnée des coordonnées actuels du robot
d // choix de la direction
5
6
tableau d entier tab de taille 4
7
8
Liste de Coordonnee al
9
10
11
12
13
14
15
16
17
18
19
20
21
22
pour i de 0 à 4
tab[i] = -1;
fin pour
// création des coordonnées des prochaines cases
Coordonnee droite = x + 1,y
Coordonnee gauche = x - 1,y
Coordonnee haut = x, y - 1
Coordonnee bas = x, y + 1
// regarde pour chaque direction si elle sont déjà en mémoire
si la case de coordonnée droite =0
alors
tab[0] = laver(droite);// si la case est dans la mémoire du robot , laver renvoie un indice correspondant à
la case dans la liste de mémoire, sinon il renvoie la taille maximum de la liste +1
23
24
25
26
si la case de coordonnée gauche =0
alors
tab[1] = laver(gauche)
27
28
29
30
si la case de coordonnée haut=0
alors
tab[2] = laver(haut)
31
32
33
34
si la case de coordonnée bas =0
alors
tab[3] = laver(bas)
35
36
37
38
39
max = 0
pour i de 0 à 4
si tab[i] > max
alors
22
40
41
max = tab[i];
fin pour
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
pour i de 0 à 4
si tab[i] = max
alors
si i = 0
alors
on ajoute en tête droite à al
sinon si i = 1
alors
on ajoute en tête gauche à al
sinon si i = 2
alors
on ajoute en tête haut à al
sinon
on ajoute en tête bas à al
57
58
59
60
fin pour
// tirage aléatoire entre les différentes dirrection restante .
d =valeut aléatoire comprise entre 0 et la taille de la liste al
61
62
63
Coordonnée du robot = coordonnée indice d dans al
on ajoute cette coordonnée à la liste mémoire
64
65
renvoie la coordonnée du robot actualisée;
23
3.2.3
Déplacement du Robot de type III
L’algorithme de déplacement du Robot de type III est construit sur les fondations de l’algorithme des
fourmis vue précédemment. Cependant, il supprime toute part d’aléatoire en se découpant en deux parties :
Première partie :
Le déplacement du robot s’effectue selon un schéma incluant des rotations dans le
sens positif et négatif des directions possibles. Le robot (possédant quatre directions : bas, droite ,haut,
gauche) va pouvoir pivoter sur lui-même afin de longer les obstacles ou les cases nettoyées, comme le
ferait un humain, ce qui lui permet de parcourir rapidement une pièce en repassant le moins possible sur
ses pas.
Deuxième partie :
Lorsque le robot se retrouve entouré d’obstacles et de cases propres, il va alors
chercher le plus court chemin entre lui et la case sale la plus proche. Pour se faire, il va réutiliser et
réorganiser les informations qu’il a enregistré de manière à récupérer les coordonnées des cases situées
autour de lui parmi la liste des cases qu’il a déjà vue. Il les trie alors dans de nouvelles listes qui seront
stockées dans un tableau évolutif selon le schéma suivant :
Figure 3.7 – Schéma explicatif montrant le déplacement du robot
24
La première liste contient les coordonnées des cases marquées à 1 ci-dessus, la deuxième celles marquées
par 2 et ainsi de suite jusqu’à la case cherchée.
Figure 3.8 – Schéma explicatif du rangement des cases
25
Algorithme du déplacement utilisant une fonction recherche pour rechercher le chemin le plus court entre
le robot et une case sale.
1
Coordonnee coutourneETrecherche(Piece p)
2
3
4
5
6
co = Coordonnées actuel du robot
x = abscisse des coordonnées actuels du robot
y = ordonnée des coordonnées actuels du robot
d // choix de la direction
7
8
tableau d entier tab de taille 4
9
10
Liste de Coordonnee al
11
12
13
14
15
16
17
18
19
20
21
22
23
pour i de 0 à 3
tab[i] = -1
fin pour
// création des coordonnées des prochaines cases
Coordonnee droite = x + 1,y
Coordonnee gauche = x - 1,y
Coordonnee haut = x, y - 1
Coordonnee bas = x, y + 1
// regarde pour chaque direction si elle sont déjà en mémoire
si la case de coordonnée droite =0
alors
tab[0] = laver(droite)
24
25
26
27
si la case de coordonnée gauche =0
alors
tab[1] = laver(gauche)
28
29
30
31
si la case de coordonnée haut=0
alors
tab[2] = laver(haut)
32
33
34
35
si la case de coordonnée bas =0
alors
tab[3] = laver(bas)
36
37
38
39
40
41
42
43
44
// on recuppère la plus grande valeur du tableau , celle que l on l ira si elle est unique
max = 0
pour i de 0 à 3
si tab[i] > max
alors
max = tab[i];
fin si
fin pour
45
46
47
48
49
50
51
52
si rechercheCase est faux //si on est pas en train d’ aller vers une case précise
alors
si max < taille de coo + 1 et p(c1) = 0
alors
lchemin = recherche() //on recherche le chemin le plus court entre le robot et une case sale .
rechercheCase = vrai
renvoie la coordonnée en tête de la liste lchemin
53
54
55
56
57
sinon
si tab[0] = max
alors
rotation dans le sens négatif des positions
26
58
59
60
61
sinon si tab[3] = max
alors
rotationP();
62
63
64
65
sinon si tab[1] =max
alors
double rotation dans le sens positif des positions
66
67
renvoie c2
68
69
70
71
sinon si taille de lchemin >= 2
alors
on supprime le premier élément de la liste lchemin
72
73
74
75
76
77
78
fin si
si taille de lchemin = 1
alors
rechercheCase = faux
fin si
renvoie le premier élément de la liste
27
3.2.4
Création de pièces
Algorithme trivial, il consiste à créer aléatoirement une pièce, dans un fichier texte, de la taille désirée
avec une probabilité d’apparition d’objets modifiable mais initialement choisie à 20% ce qui nous semblait
le plus réaliste. Cet algorithme a comme défaut de générer des pièces qui ne peuvent pas être exploitables
directement. En effet, les obstacles étant aléatoires, nous pouvons nous retrouver avec une case enfermée
ou même que le robot soit bloqué, ne pouvant accéder à aucune case, ce qui nous oblige à traiter ces
éventuelles problèmes.
3.2.5
Algorithme de correction
Nous avons alors conçu un algorithme permettant de corriger les éventuels défauts qu’une pièce peut
avoir, notamment les défauts vus précédemment où une case peut-être entourée d’obstacles et donc être
inaccessible rendant le nettoyage de la pièce inexploitable. Cet algorithme, construit de manière récursive,
va, en quelque sorte, scanner la pièce en se divisant en 4 branches maximum, avec comme point de départ,
le coin en bas gauche (position initiale du robot), ce qui va nous permettre de vérifier l’accessibilité de
chacune des cases qu’il va stocker dans leurs intégralité dans une liste de coordonnées en ne stockant
jamais deux fois la même case, et ce jusqu’à ce qu’il n’y est plus de cases accessibles qui ne soient dans la
liste.
Ainsi nous construisons une pièce initialement remplie d’obstacles. Puis, à l’aide de la liste de stockage
des coordonnées précédentes, nous transformons les cases de la nouvelle pièce, qui ont leur coordonnée
dans la liste, en cases accessibles et sales.
Au final, nous obtenons une nouvelle pièce revue et corrigée, qui nous assure le bon déroulement du
ménage qu’effectuera le robot.
Algorithme de correction de la pièce utilisant la procédure scan.
1
2
//
renvoie une matrice d’ entier à 2 dimensions
correction(matrice d’entier à 2 dimensions tab, entier nbLigne, entier nbColonne)
3
4
5
6
7
8
9
10
11
Liste de coordonnées l
scan(coordonnée abscisse 1 et ordonnée nbLigne-2, tab);
matrice 2D tabNew
pour i de 0 à nbLigne-1
pour j de 0 à nbColonne-1
tabNew[i][j] = 1;
fin pour
fin pour
12
13
14
15
16
17
18
19
entier x, y
pour i de 0 à taille de l -1
x = l abscisse de l iéme coordonnée de l
y = l ordonné de l iéme coordonnée de l
tabNew[y][x] = 0;
fin pour
renvoietabNew;
Algorithme de la procédure scan.
1
2
3
4
5
scan(Coordonnee c, Matrice 2D d’entier
c1 = coordonnée avec abcisse de c
c2 = coordonnée avec abcisse de c
c3 = coordonnée avec abcisse de c
c4 = coordonnée avec abcisse de c
tab) {
et ordonnée de
et ordonnée de
+1 et ordonnée
-1 et ordonnée
c +1
c -1
de c
de c
28
6
si c1 n appartient pas à l et tab[ordonnée de c1][abcisse de c1] = 0
alors
on ajoute en tête c1 à l et on relance scan(c1, tab)
fin si
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
si c2 n appartient pas à
alors
on ajoute en tête c2
fin si
si c3 n’appartient pas à
alors
on ajoute en tête c3
fin si
si c4 n appartient pas à
alors
on ajoute en tête c4
fin si
fin procedure
3.2.6
l e tab[ordonnée de c2][abcisse de c2] = 0
à l et on relance scan(c2, tab)
l e tab[ordonnée de c3][abcisse de c3] = 0
à l et on relance scan(c3, tab)
l e tab[ordonnée de c4][abcisse de c4] = 0
à l et on relance scan(c4, tab)
Algorithme de « contamination »
Durant la réflexion sur le projet, nous avons imaginé plusieurs fonctions permettant de nettoyer une pièce.
Parmi elles, nous avons été très intéressé par la fonction que nous avons appelé l’algorithme de « contamination ».
Ce nom lui a été donné car tel un virus, dès que le robot passe sur une case, il doit parcourir toutes les
cases alignées verticalement et horizontalement à celle-ci jusqu’à toucher un obstacle et ce ainsi de suite.
Grâce à cette fonction, nous sommes sûr de laver toutes les cases de la pièce mais nous n’avons pas pu la
mettre à exécution car elle ne rentrait pas dans les critères des robots. Néanmoins nous nous en sommes
inspiré pour la création de l’algorithme précédant qui corrige les pièces.
29
3.3
Interface graphique
Interface visuelle « SeanceMenage » Comme son nom l’indique « SeanceMenage » est l’interface qui
nous permet de visualiser la séance de ménage. Elle utilise donc une classe Menage dont elle exécute la
procédure principale permettant d’effectuer le ménage de la pièce. Afin d’avoir une visualisation dynamique de la scène, nous avons utilisé des Thread, c’est-à-dire des processus qui s’exécutent en parallèle du
programme principal, ceci nous a permis entre autre de mettre du son (à la scène) mais aussi d’effectuer
un avancement temporel réel de la séance de ménage effectuée par le robot.
La salle à nettoyer est générée en dessin par des fonctions de type « draw » et s’adapte aux dimensions de
la pièce.
Figure 3.9 – Fenêtre principale permettant de visualiser le ménage
30
Interface visuelle « PageAccueil »
C’est l’interface graphique principale du programme. Elle présente
à l’utilisateur les différentes interactions possibles entre lui et le programme, notamment la consultation
des statistiques, la création ou le chargement de nouvelles pièces, les paramètres de temps imparti pour le
nettoyage d’une pièce ainsi que l’échelle de temps pour un déplacement du robot ou encore la possibilité
de choisir une musique à écouter lors de la séance de ménage.
Figure 3.10 – Fenêtre d’accueil
31
4
Statistiques
Il nous semblait essentiel que figure dans le programme des données sur la performance des robots, sous
forme de statistiques. C’est pourquoi nous avons implémenté une interface graphique pour les statistiques.
4.1
Conception
Les statistiques
Les statistiques sont triés tout d’abord en fonction des pièces. En effet, après le passage
d’un robot sur une pièce on génère une donnée qui contient la pièce nettoyée, la durée de la séance de
ménage et si le robot à pu nettoyer entièrement la pièce ou non. Ensuite la donnée est classée en fonction
des dimensions de la pièce et de son pourcentage d’obstacles, sachant que si la pièce est déjà dans les
données des statistiques, on complète les anciennes données, ce qui nous permet de bien comparer les
robots. Puis on affiche la moyenne de temps qu’à mis chaque robot pour nettoyer une pièce, ainsi que le
nombre de nettoyage qu’a effectué le robot sur une pièce, ce qui nous permet d’évaluer la fiabilité des
statistiques en fonction du nombre de fois qu’un ou plusieurs robots ont lavé une pièce. De plus si un
robot n’a pas pu nettoyer entièrement la pièce, la cellule contenant sa moyenne de temps pour cette pièce
devient rouge.
La gestion des statistiques : Afin d’assurer le suivi des statistiques, à chaque nouvelle donnée ajoutée,
ils sont sauvegardés dans un fichier du nom de « saveStatistique » et chargés automatiquement lors du
lancement du programme. Ainsi l’utilisateur n’a pas besoin de se soucier de la gestion des statistiques
qui est complètement automatisée. Néanmoins il peut effacer toutes les données collectées s’il le souhaite
grâce à l’interface principale, ou tout simplement en supprimant le fichier ou en le renommant car toutes
les exceptions sont gérées, et si une modification est apportée au fichier de sauvegarde, un nouveau fichier
de sauvegarde sera recréé et réinitialisé.
Échelle réelle :
Nous avons effectué des tests en prenant comme échelle de temps le temps que met
un robot aspirateur à nettoyer 1 m2 en moyenne, soit d’une minute pour une surface lisse. Ainsi nous
pouvons définir une case de la pièce comme 1 m2 . Nous pouvons donc apporter une simulation plus
perspicace quant à la performance des différents robots.
32
4.2
Exploitation
4.2.1
Vision globale
Nous avons comparé la capacité de chaque robot à nettoyer 9 pièces différentes. Les 3 premières ont une
même dimension de 100 m2 mais avec des taux d’obstacles différents et en affectant une mémoire par
défaut de 500 au deuxième robot. Les 3 suivantes différents simplement des trois dernières par leurs
dimensions communes de 300 m2 . Les 3 dernières ont une dimensions de 500 m2 .
En effectuant 100 tests par pièce et par robot et en prenant 500 comme taille mémoire du deuxième robot
nous obtenons ainsi les tableaux suivants :
Pièce (m2 /% d’obstacles)
100/0
100/10
100/20
300/0
300/10
300/200
Robot sans mémoire
22 :58 :22
24 :44 :36
30 :41 :28
non réussi
non réussi
non réussi
Robot 500 de mémoire
01 :40 :00
02 :59 :00
02 :52 :00
05 :00 :00
16 :48 :00
05 :58 :00
Robot mémoire infinie
01 :40 :00
01 :44 :00
01 :44 :00
05 :00 :00
5 :18 :00
03 :45 :00
Pièce
(m2 /%
d’obstacles)
500/0
500/10
500/20
Robot sans mémoire
non réussi
non réussi
non réussi
Robot 500 de mémoire
08 :20 :00
32 :14 :00
20 :57 :00
Robot mémoire infinie
08 :20 :00
08 :25 :00
08 :57 :00
Nous constatons graphiquement une différence significative entre la performance de chaque robot. De
plus, le temps mis pour le nettoyage par le deuxième robot croit lorsqu’on passe à 10% d’obstacles par
pièce mais décroit lorsque le pourcentage d’obstacles passe à 20%. Nous avons donc ici une vue synthétique de la performance de chaque robot.
33
4.2.2
Statistiques en fonction des dimensions des pièces
En effectuant une étude des 3 types de robots et des deux stratégies du deuxième robot, en variant la
mémoire de celui-ci, sur 10 pièces de dimensions différentes et de pourcentages d’obstacles identiques,
on obtient le résultat suivant, sachant que la deuxième stratégie du robot de type 2 utilise l’algorithme des
fourmis et la première utilise le schéma de coloriage :
On constate que le premier robot n’a pas pu nettoyer les pièces de plus de 190 m2 en moins de 99 heures et
que le deuxième robot utilisant la deuxième stratégie et ayant une mémoire de 50,n’a pas réussi à nettoyer
les pièces de plus de 484 m2 . De plus la première stratégie du deuxième robot n’a permis de laver aucune
pièce lorsque sa mémoire était de 50. On peut donc dire que la première stratégie du deuxième robot n’est
pas du tout adaptée à une petite mémoire en comparaison à sa deuxième stratégie. L’efficacité du premier
robot est très limitée et faible comparée aux deux autres robots.
De plus pour les pièces en dessous de 324 m2 , les deux stratégies du robot de type 2 ont une efficacité
similaire pour une mémoire supérieure à 500 bien que légèrement moins efficace que le troisième robot.
L’efficacité gagnée par l’augmentation de la mémoire du deuxième robot n’est significative que pour les
pièces de dimensions supérieures à 400 m2 pour la deuxième stratégie du robot alors que pour la première
stratégie, la différence ce creuse à partir de 300 m2 . De plus, pour une mémoire de 5000 les deux stratégies
ont la même efficacité à partir de 400 m2 et la deuxième stratégie se montre en moyenne plus efficace que
la première pour une mémoire inférieure.
On conclut que la deuxième stratégie du robot de type 2 est la plus intéressante des deux pour gérer
l’évolution des dimensions des pièces bien que toujours inférieure à l’efficacité du troisième robot.
34
4.2.3
Statistiques en fonction du pourcentage d’obstacles des pièces
En faisant de même que précédemment mais cette fois-ci en variant uniquement le pourcentage d’obstacles
de chaque pièce, nous obtenons le résultat suivant :
On constate que le premier robot ainsi que le deuxième robot qui utilisait la première stratégie pour une
mémoire de 50 n’ont pas pu laver une seule pièce. Ils sont donc peu efficaces. La deuxième stratégie du
robot de type 2 se montre de nouveau plus efficace car elle permet de laver 8 pièces sur 9.
Néanmoins la première stratégie se montre plus pertinente en moyenne que l’autre pour une mémoire de
500 et 5000 sur toute l’étude. On peut voir aussi que la différence de mémoire pour les deux stratégies n’a
plus d’effet à partir de 23% d’obstacles par pièce. De plus, pour un pourcentage d’obstacles supérieur à
23%, la première stratégie augmente l’efficacité du deuxième robot, ce phénomène se produit aussi avec
la deuxième stratégie mais à partir de 35% d’obstacles. La deuxième stratégie permet aussi au robot une
plus grande stabilité en moyenne sur l’évolution des obstacles que la première stratégie.
On remarque quand même que le troisième robot est peu affecté par l’augmentation du pourcentage
d’obstacles des pièces. Il se révèle donc d’une très grande efficacité par rapport aux autres robots.
On conclut donc que l’utilisation de la première stratégie pour 500 et 5000 de mémoire est plus pertinente
que la deuxième, permettant au robot une meilleure stabilité et efficacité.
Conclusion des statistiques On constate que les deux stratégies utilisées par le deuxième robot ont chacune leurs avantages. La première est plus efficace pour de grandes mémoires et pour gérer les obstacles
alors que la deuxième est plus efficace pour de petites mémoires mais aussi pour gérer la taille des pièces.
On peut donc penser qu’un mariage entre les deux stratégies constituerait une base solide et efficace pour
un robot. Néanmoins on constate qu’aucune stratégie utilisée, même avec une grande mémoire ne peut
permettre à un robot de deuxième type à rivaliser avec le troisième. Le premier robot quand à lui, se
montre peu efficace en toutes circonstances.
35
5
Validation
Pour comprendre les test avec JUnit : JUnit est un framework permettant de réaliser des tests unitaires
sur du code Java. Le principal intérêt est de s’assurer que le code répond toujours au besoin même après
d’éventuelles modifications. On peut donc automatiser les tests. Ceux ci sont exprimés dans des classes
sous la forme de cas de tests avec leurs résultats attendus. JUnit exécute ces tests et les compare avec ces
résultats, la validité des tests est matérialisé par une barre d’état colorée (rouge les tests n’ont pas tous été
validés, vert ils l’ont tous été).
JUnit nous permet de tester chaque fonction. Les tests peuvent être effectués de différentes manières, mais
l’idée générale est d’utiliser chaque fonctionnalité de la méthode que l’on veut tester afin de s’assurer
que toutes les utilisations de celle-ci répondent aux attentes. Pour ce faire, nous utilisons cette dernière
puis nous comparons les résultats obtenus avec les résultats attendus. C’est à dire que nous devons évaluer
quelle sera le résultat d’une utilisation de la méthode, et comparer cette attente avec le résultat réel obtenu.
C’est ce que nous permet de faire JUnit.
Ainsi si nous voulons comparer des assertions, il nous suffira d’utiliser la commande assertTrue() qui
permet de vérifier qu’une assertion est vrai. Si elle l’est, le test sera considéré comme validé et nous
passerons aux autres tests. On peut effectuer autant de test que l’on désire dans une classe JUnit, à savoir
que la classe de test n’est validée que si tous les tests la composant le sont. De plus, si tous les test ne sont
pas passés, nous pouvons accéder directement aux tests qui n’ont pas été validés afin d’en comprendre la
raison.
Junit possède plusieurs méthodes de tests :
– assertEquals -vérifie que deux objets sont égaux
– assertFalse -vérifie que l’expression est fausse
– assertTrue -vérifie que l’expression est vrai
– assertNotNull -vérifie que l’objet n’est pas nul
– assertNull-vérifie qu’un objet est nul
– assertNotSame -vérifie que deux références ne sont pas les mêmes
– assertSame -vérifie que deux références sont les mêmes
– fail -provoque l’échec forcé du test
L’utilisation de JUnit pour effectuer les tests unitaires nous a permis d’assurer tout au long du développement du programme, la fonctionnalité de chacune de nos classes et ce malgré les multiples changements
que l’on peut effectuer. L’importance des tests avec JUnit est renforcée par le travail en équipe qui nécessite
la certitude du bon fonctionnement du programme malgré les modifications apportées, sans pour autant
que chaque personne n’ait besoin de démontrer qu’elle n’entrave pas le bon déroulement du programme.
Les tests unitaires effectués avec JUnit sur les classes les plus importantes du programme sont fournis en
annexe.
36
6
L
Exploitation
ors du lancement du programme nous nous trouvons sur cette page d’accueil offrant diverses interactions avec l’utilisateur.
Ce dernier peut modifier le robot utilisé, initialement le robot de type I, en le remplaçant par l’un des
deux autres robots possibles. S’il sélectionne le robot de type II, il pourra, s’il le souhaite déterminer la
taille de la mémoire du robot, initialisée par défaut à 500.
Figure 6.1 – Visualisation du changement de la fenêtre selon le robot sélectionné
37
L’utilisateur peut aussi interagir sur le temps que met le robot à se déplacer d’une case, et sur le temps
imparti pour effectuer le ménage
Figure 6.2 – Les modifications de temps
Il peut aussi consulter ou réinitialiser les statistiques sur les différents déplacements des trois robots. Ses
statistiques sont basées sur toutes les pièces qui ont été visitées par au moins un robot. Si un robot nettoie
plusieurs fois la même pièce le temps affiché est une moyenne du temps de ménage pour cette pièce et
pour ce robot. Cependant si parmi les multiples nettoyages le robot n’a pas entièrement lavé la pièce,
l’utilisateur est prévenu grâce à une coloration rouge de la moyenne du temps.
Figure 6.3 – Les statistiques
38
L’utilisateur a aussi la possibilité de charger une musique en cliquant sur le deuxième bouton « Parcourir »
qui lui permet de choisir un fichier de musique au format wav.
Figure 6.4 – Action du bouton parcourir
Si le fichier n’est pas au format wav, une fenêtre d’erreur (ci-dessous) s’ouvre pour le lui signaler.
Figure 6.5 – Fenêtre d’erreur de format
39
L’utilisateur peut charger une pièce existante en cliquant sur le bouton Parcourir à droite de la liste déroulante. Il peut aussi, s’il le désire créer une nouvelle pièce en cliquant sur le bouton Créer une pièce, ce qui
ouvre une nouvelle fenêtre Création pièce. Dans les deux cas, la liste déroulante qui possède initialement
la pièce piece0.txt ajoutera la nouvelle pièce.
Figure 6.6 – Les divers actions pour ajouter une pièce
Si l’utilisateur a cliqué sur le bouton « Créer une pièce », la fenêtre ci-dessous s’ouvre.
Figure 6.7 – Explications de la fenêtre Création pièce
40
En cliquant sur le bouton Voir l’utilisateur peut visualiser dans une nouvelle fenêtre la pièce sélectionnée
dans la liste déroulante. En cliquant sur le bouton Lancer, si tous les paramètres choisis par l’utilisateur
sont correctes, la fenêtre permettant de visualiser la séance de ménage s’ouvre, sinon c’est une fenêtre
d’erreur qui s’affiche en spécifiant l’erreur trouvée.
Figure 6.8 – Visualisation des actions des boutons Voir et Lancer
41
La fenêtre effectuant le ménage offre plusieurs choix pour le déroulement de la séance, tels que :
-la mise en marche ou en pause de la séance de nettoyage,
Figure 6.9 – Explications de la fenêtre Séance Ménage
42
-le type de déchets à ramasser,
Figure 6.10 – Les différents plateaux de test
-l’activation ou non du bruit du robot,
Figure 6.11 – Volet de gestion du bruit émis par le robot
43
-la lecture ou l’arrêt de la musique choisie au préalable.
Figure 6.12 – Volet de gestion de la musique
44
A la fin du ménage effectué par le robot, une fenêtre ouvre et annonce le résultat de la séance. Si elle s’est
parfaitement bien déroulée et que la pièce est propre dans le temps imparti elle affiche le temps que le
robot à mis pour laver la pièce :
Figure 6.13 – Fenêtre de fin de ménage en cas de réussite du robot
Si la séance de ménage de la pièce n’a pas pu être lavée dans le temps imparti elle affiche le nombre de
cases lavées :
Figure 6.14 – Fenêtre de fin de ménage en cas d’échec du robot
45
7
Conclusion
râce à une conception méthodique divisée en plusieurs phases (phase d’analyse, phase de dévelop-
G
pement, phase de validation), nous avons conçu ce programme de simulation de sorte à répondre à
toutes les attentes. Bien qu’assez simple, il a été construit de façon à être le plus modulable possible et permet via ses nombreuses options d’étudier les différents types de robots. Suite à l’analyse des statistiques
sur plusieurs jeux d’essais, nous pouvons constater une différence colossale du point de vue du rendement entre un robot sans mémoire et un robot dont sa taille de mémoire est proportionnelle au périmètre
de la pièce. En effet, pour un robot qui n’aurait pas une mémoire infinie, la taille optimale de sa mémoire
serait le périmètre interne de la pièce. Si sa taille est inférieure, ses performances chuteront mais resteront
malgré tout supérieures à celle du robot sans mémoire. Dans le cas d’un robot utopique, ses performances
sont incomparables aux deux autres et ce quelque soit la pièce utilisée. L’élaboration des différents algorithmes permettant le déplacement du robot, et les problèmes rencontrés suite au contraintes de chaque
robot, nous sensibilise d’avantage à la complexité algorithmique que pose la réalisation d’un programme
permettant de guider un robot dans la réalité. En effet, nous avions pensé dans un premier temps à des
algorithmes récursifs, mais ceux-ci étant bien trop couteux en calculs et ne remplissant pas toutes les
exigences nécessaires au robot, cette première idée fut avortée. Bien que l’on puisse améliorer nos algorithmes finaux, ceux-ci s’avèrent plutôt efficaces. De plus notre programme s’avère relativement robuste
grâce à la gestion et à l’organisation du maximum d’exceptions. Ce projet nous aura permis d’approfondir
nos connaissances algorithmiques suite aux recherches menées sur différents algorithmes, notamment de
recherche du plus court chemin tels que Djikstra, A*,...etc, mais aussi sur les outils de programmation Java
tels que les JUnits, les Thread,...etc. Le terme robot est un terme Hongrois qui signifie « Homme », mais nous
pouvons voir que malgré l’avancée technologique des robots aspirateurs, ils sont encore loin de réaliser le
nettoyage aussi efficacement et rapidement qu’un homme. Néanmoins les derniers robots peuvent désormais construire des murs infrarouge pour diminuer leurs déplacements, mais aussi évaluer les distances,
ce qui laisse encore présager de bons espoirs quand au remplacements de nos balais et aspirateurs par ces
bijoux de technologie, couteux mais pratique.
Biblisitographie
– JUnit - http://junit.sourceforge.net/
– Le Site Developpez.com - http://gfx.developpez.com/tutoriel/java/junit/
– Le Site Developpez.com - http://viennet.developpez.com/cours/java/thread/
– recherche sur les robots aspirateur -http://choisirsonaspirateur.free.fr/aspirateur-robot
– Wikipedia -http://fr.wikipedia.org/wiki/Algorithme_de_Dijkstra
– Le Site Developpez.com -http://khayyam.developpez.com/articles/algo/astar/
– Site de Mickael Péchaud -http://mickaelpechaud.free.fr/cours/tris.pdf
– Le Site Labo.algo -http://labo.algo.free.fr/pvc/algorithme_colonie_de_fourmis.html
46
8
Annexe
Test unitaires
ous avons effectué une partie de nos tests en choisissant d’utiliser des JUnits. Les tests qui nous
N
semblaient important de montrer sont ceux concernant le noyau du programme les classes des robots,
la classe Piece et la classe Menage. Les autres classe étant un exemple d’ implémentation graphique et
d’utilisation des classe ci-dessus, nous avons décidé de ne pas utiliser de JUnit pour eux, puisque notre
programme est conçu de manière à pouvoir implémenter les classe de diverses marnières, voir avoir
plusieurs implémentations différentes en même temps,il ne nous a pas semblé nécessaire de faire figurer
les tests effectués sur les autres classe. Pour chaque classe testée, nous testons les fonctions qui contiennent
des boucles et leurs fonctions principales.
47
test de la classe « RI »
Figure 8.1 – testRI
Code JUnit de « testRI »
1
public classe RITest {
2
3
4
5
6
7
8
9
10
11
12
13
14
/∗∗
∗ Test de la fonction Aleatoire de la classe RI.
∗/
@Test
public void testAleatoire() throws Exception {
/∗ Piece test :
000000001000
001101000011
100011000000
001000000001
001110000000
∗/
15
16
17
System.out.println("Test la fonction aleatoire()");
Piece p = new Piece(new File("pieceTest.txt"));
18
19
20
// on créait une instance de RI
21
22
RI r1 = new RI(p.getNbLigne());
23
24
25
26
Coordonnee droite = new Coordonnee(2, 5);
Coordonnee haut = new Coordonnee(1, 4);
Coordonnee result = r1.aleatoire(p);
27
28
29
30
// on vérifie que la coordonnée renvoyé est bien l ’ une des quatres
assertTrue((droite.getX() == result.getX() && droite.getY() == result.getY())
|| (haut.getX() == result.getX() && haut.getY() == result.getY()));
31
32
33
34
// on le place en 7;4
r1.setC(7, 4);
48
35
36
droite = new Coordonnee(8, 4);
Coordonnee gauche = new Coordonnee(6, 4);
haut = new Coordonnee(7, 3);
Coordonnee bas = new Coordonnee(7, 5);
result = r1.aleatoire(p);
37
38
39
40
41
42
// on vérifie que la coordonnée renvoyé est bien l ’ une des quatres
assertTrue((droite.getX() == result.getX() && droite.getY() == result.getY())
|| (gauche.getX() == result.getX() && gauche.getY() == result.getY())
|| (bas.getX() == result.getX() && bas.getY() == result.getY())
|| (haut.getX() == result.getX() && haut.getY() == result.getY()));
43
44
45
46
47
48
// on le place en 4;3
r1.setC(4, 3);
49
50
51
52
gauche = new Coordonnee(3, 3);
53
54
bas = new Coordonnee(4, 4);
result = r1.aleatoire(p);
55
56
57
// on vérifie que la coordonnée renvoyé est bien l ’ une des deux possibles
assertTrue((gauche.getX() == result.getX() && gauche.getY() == result.getY())
|| (bas.getX() == result.getX() && bas.getY() == result.getY()));
58
59
60
61
62
63
}
}
49
test de la classe « RII »
Figure 8.2 – testRII
Code JUnit de « testRII »
1
public class RIITest {
2
3
4
5
6
7
/∗∗
∗ Test la fonction fourmieAl de la class RII .
∗/
@Test
public void testFourmieAl() throws Exception {
8
9
10
11
12
13
14
15
/∗ Piece test :
000000001000
001101000011
100011000000
001000000001
001110000000
∗/
16
17
18
19
20
System.out.println("Test de fourmieal()");
Piece p = new Piece(new File("pieceTest.txt"));
// on créait une instance de RII de taille memoire de 5
RII r2 = new RII(p.getNbLigne(), 5);
21
22
23
24
25
26
27
Coordonnee droite = new Coordonnee(2, 5);
Coordonnee haut = new Coordonnee(1, 4);
Coordonnee result = r2.fourmieAl(p);
// on vérifie que la coordonnée renvoyé est bien l ’ une des quatres
assertTrue((droite.getX() == result.getX() && droite.getY() == result.getY())
|| (haut.getX() == result.getX() && haut.getY() == result.getY()));
28
29
30
// on le place en 7;4
r2.setDeplacement(7, 4);
31
32
33
34
35
36
37
droite = new Coordonnee(8, 4);
Coordonnee gauche = new Coordonnee(6, 4);
haut = new Coordonnee(7, 3);
Coordonnee bas = new Coordonnee(7, 5);
result = r2.fourmieAl(p);
50
// on vérifie que la coordonnée renvoyé est bien l ’ une des quatres
assertTrue((droite.getX() == result.getX() && droite.getY() == result.getY())
|| (gauche.getX() == result.getX() && gauche.getY() == result.getY())
|| (bas.getX() == result.getX() && bas.getY() == result.getY())
|| (haut.getX() == result.getX() && haut.getY() == result.getY()));
38
39
40
41
42
43
44
45
// on le place en 4;3
r2.setDeplacement(4, 3);
46
47
48
49
gauche = new Coordonnee(3, 3);
50
51
bas = new Coordonnee(4, 4);
result = r2.fourmieAl(p);
52
53
54
// on vérifie que la coordonnée renvoyé est bien l ’ une des deux possibles
assertTrue((gauche.getX() == result.getX() && gauche.getY() == result.getY())
|| (bas.getX() == result.getX() && bas.getY() == result.getY()));
55
56
57
58
// si le robot est desscendu on regarde s ’ il ne remonte pas
if ((bas.getX() == result.getX() && bas.getY() == result.getY())) {
droite = new Coordonnee(5, 4);
result = r2.fourmieAl(p);
59
60
61
62
63
// on vérifie que la coordonnée renvoyé est bien la seule possible
assertTrue((droite.getX() == result.getX() && droite.getY() == result.getY()));
64
65
66
} else {
gauche = new Coordonnee(2, 3);
67
68
69
result = r2.fourmieAl(p);
70
71
assertTrue((gauche.getX() == result.getX() && gauche.getY() == result.getY()));
72
}
73
74
75
76
77
}
78
79
80
81
82
83
84
85
/∗∗
∗ Test la fonction fourmieD de la class RII .
∗/
@Test
public void testFourmieD() throws Exception {
System.out.println("Test de fourmieD()");
Piece p = new Piece(new File("pieceTest.txt"));
86
87
88
// on créait une instance de RII de taille
RII r2 = new RII(p.getNbLigne(), 5);
mémoire de 5
89
90
91
92
Coordonnee droite = new Coordonnee(2, 5);
Coordonnee haut = new Coordonnee(1, 4);
Coordonnee result = r2.fourmieD(p);
93
94
95
96
// on vérifie que la coordonnée renvoyé est bien l ’ une des quatres
assertTrue((droite.getX() == result.getX() && droite.getY() == result.getY())
|| (haut.getX() == result.getX() && haut.getY() == result.getY()));
97
51
98
// on le place en 7;4
r2.setDeplacement(7, 4);
99
100
101
102
droite = new Coordonnee(8, 4);
Coordonnee gauche = new Coordonnee(6, 4);
haut = new Coordonnee(7, 3);
Coordonnee bas = new Coordonnee(7, 5);
result = r2.fourmieD(p);
103
104
105
106
107
108
// on vérifie que la coordonnée renvoyé est bien la droite
assertTrue((droite.getX() == result.getX() && droite.getY() == result.getY()));
109
110
111
112
113
// on le place en 4;3
r2.setDeplacement(4, 3);
114
115
116
117
gauche = new Coordonnee(3, 3);
118
119
bas = new Coordonnee(4, 4);
result = r2.fourmieD(p);
120
121
122
// on vérifie que la coordonnée renvoyé est bien l ’ une des deux possibles
assertTrue((gauche.getX() == result.getX() && gauche.getY() == result.getY())
|| (bas.getX() == result.getX() && bas.getY() == result.getY()));
123
124
125
126
// si le robot est desscendu on regarde s ’ il ne remonte pas
if ((bas.getX() == result.getX() && bas.getY() == result.getY())) {
droite = new Coordonnee(5, 4);
result = r2.fourmieD(p);
127
128
129
130
131
// on vérifie que la coordonnée renvoyé est bien la seule possible
assertTrue((droite.getX() == result.getX() && droite.getY() == result.getY()));
132
133
134
} else {
gauche = new Coordonnee(2, 3);
135
136
137
result = r2.fourmieD(p);
138
139
assertTrue((gauche.getX() == result.getX() && gauche.getY() == result.getY()));
140
}
141
142
}
143
144
145
146
147
148
/∗∗
∗ Test la fonction strategie de la class class RII .
∗/
@Test
public void testStrategie() throws Exception {
149
150
151
152
153
System.out.println("Test la Strategie");
Piece p = new Piece(new File("pieceTest.txt"));
// on créait une instance de RII de taille memoire de 5
RII r2 = new RII(p.getNbLigne(), 5);
154
155
156
// puisque on utilise le même principe que précédemment, on a juste à tester si le shema fonctionne donc si on
contourne l ’ obstacle
Coordonnee droite = new Coordonnee(2, 5);
52
Coordonnee haut = new Coordonnee(1, 4);
Coordonnee result = r2.strategie(p);
157
158
159
assertTrue((droite.getX() == result.getX() && droite.getY() == result.getY()));
160
161
result = r2.strategie(p);
haut = new Coordonnee(2, 4);
assertTrue((haut.getX() == result.getX() && haut.getY() == result.getY()));
result = r2.strategie(p);
haut = new Coordonnee(2, 3);
assertTrue((haut.getX() == result.getX() && haut.getY() == result.getY()));
162
163
164
165
166
167
168
result = r2.strategie(p);
droite = new Coordonnee(3, 3);
assertTrue((droite.getX() == result.getX() && droite.getY() == result.getY()));
169
170
171
}
172
173
}
53
test de la classe « RIII »
Figure 8.3 – testRIII
Code JUnit de « testRIII »
1
2
3
4
5
6
7
8
9
10
public class RIIITest {
/∗∗
∗ Test la fonction deplacement de la class RIII .
∗/
@Test
public void testDeplacement() throws Exception {
System.out.println("Test le déplacement");
Piece p = new Piece(new File("pieceTest.txt"));
// on créait une instance de RIII
RIII r3 = new RIII(p.getNbLigne());
11
// tester si le shema fonctionne donc si on contourne l ’ obstacle
Coordonnee droite = new Coordonnee(2, 5);
Coordonnee haut = new Coordonnee(1, 4);
Coordonnee result = r3.deplacement(p);
12
13
14
15
16
assertTrue((droite.getX() == result.getX() && droite.getY() == result.getY()));
17
18
result = r3.deplacement(p);
haut = new Coordonnee(2, 4);
assertTrue((haut.getX() == result.getX() && haut.getY() == result.getY()));
result = r3.deplacement(p);
haut = new Coordonnee(2, 3);
assertTrue((haut.getX() == result.getX() && haut.getY() == result.getY()));
19
20
21
22
23
24
25
result = r3.deplacement(p);
droite = new Coordonnee(3, 3);
assertTrue((droite.getX() == result.getX() && droite.getY() == result.getY()));
26
27
28
29
}
30
31
32
33
34
35
36
@Test
public void recherche() throws Exception {
System.out.println("Test recherche()");
Piece p = new Piece(new File("pieceTest.txt"));
// on créait une instance de RIII
RIII r3 = new RIII(p.getNbLigne());
54
37
// on deplace le robot :
r3.setDeplacement(2, 5, p);
r3.setDeplacement(2, 4, p);
r3.setDeplacement(2, 3, p);
r3.setDeplacement(3, 3, p);
r3.setDeplacement(2, 3, p);
r3.setDeplacement(2, 4, p);
r3.setDeplacement(1, 4, p);
// suite à ses déplacement , le robot se retrouve
la plus proche est en 2,2
38
39
40
41
42
43
44
45
46
isolée et on peut lancer la création de la recherche la case sale
47
ListeChaine<Coordonnee> test = r3.recherche();
assertTrue(r3.getCaseCherche().getX() == 2 && r3.getCaseCherche().getY() == 2);
48
49
50
// le chemin qui y mène doit être 2,4 2,3
assertTrue(test.selectionner(0).getX() == 2 && test.selectionner(0).getY() == 4);
assertTrue(test.selectionner(1).getX() == 2 && test.selectionner(1).getY() == 3);
51
52
53
54
// on verifie
55
la
taille de la liste
56
assertEquals(test.taille(), 2);
57
58
// test si le robot se déplace comme voulu
Coordonnee c = r3.deplacement(p);
assertTrue(c.getX() == 2 && c.getY() == 4);
c = r3.deplacement(p);
assertTrue(c.getX() == 2 && c.getY() == 3);
c = r3.deplacement(p);
assertTrue(c.getX() == 2 && c.getY() == 2);
59
60
61
62
63
64
65
66
}
67
68
}
55
test de la classe « Piece »
Figure 8.4 – testPiece
Code JUnit de « testPiece »
1
public class PieceTest {
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/∗∗
∗ Test la fonction piecePropre de la class Piece .
∗/
@Test
public void testPiecePropre() {
System.out.println("Test de la fonction PiecePropre()");
/∗ Piece test :
000000001000
001101000011
100011000000
001000000001
001110000000
∗/
16
17
18
19
20
21
22
23
24
Piece p = new Piece(new File("pieceTest.txt"));
// la liste des coordonnées des cases sales dans la pièces est :
// 1,1 1,2 1,3 1,4 1,5 1,6 1,7 1 ,8 1,10 1,11 1,12
// 2,1 2,2 2,5 2,7 2,8 2,9 2,10
// 3,2 3,3 3,4 3,7 3,8 3,9 3,10 3,11 3,12
// 4,1 4,2 4,3 4,4 4,5 4,6 4,7 4,8 4,9 4,10 4,11
// 5,1 5,2 5,6 5,7 5,8 5,9 5,10 5,11 5,12
25
26
27
28
29
30
31
32
33
ListeChaine<Coordonnee> lc = new
// on remplie la liste
lc.ajouterTete(new Coordonnee(1,
lc.ajouterTete(new Coordonnee(2,
lc.ajouterTete(new Coordonnee(3,
lc.ajouterTete(new Coordonnee(4,
lc.ajouterTete(new Coordonnee(5,
lc.ajouterTete(new Coordonnee(6,
ListeChaine<Coordonnee>();
1));
1));
1));
1));
1));
1));
56
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
Coordonnee(7, 1));
Coordonnee(8, 1));
Coordonnee(10, 1));
Coordonnee(11, 1));
Coordonnee(12, 1));
Coordonnee(1, 2));
Coordonnee(2, 2));
Coordonnee(5, 2));
Coordonnee(7, 2));
Coordonnee(8, 2));
Coordonnee(10, 2));
Coordonnee(9, 2));
Coordonnee(2, 3));
Coordonnee(3, 3));
Coordonnee(4, 3));
Coordonnee(9, 3));
Coordonnee(7, 3));
Coordonnee(8, 3));
Coordonnee(10, 3));
Coordonnee(11, 3));
Coordonnee(12, 3));
Coordonnee(1, 5));
Coordonnee(2, 5));
Coordonnee(12, 5));
Coordonnee(6, 5));
Coordonnee(7, 5));
Coordonnee(8, 5));
Coordonnee(9, 5));
Coordonnee(10, 5));
Coordonnee(11, 5));
Coordonnee(1, 4));
Coordonnee(2, 4));
Coordonnee(3, 4));
Coordonnee(4, 4));
Coordonnee(5, 4));
Coordonnee(6, 4));
Coordonnee(7, 4));
Coordonnee(8, 4));
Coordonnee(9, 4));
Coordonnee(10, 4));
Coordonnee(11, 4));
75
76
77
// on test avec une liste complette contenant toutes les case sale , si PiecePropre renvoie vrai
assertTrue(p.piecePropre(lc));
78
79
80
p = new Piece(new File("pieceTest.txt"));
81
82
lc = new ListeChaine<Coordonnee>();
83
84
85
86
87
88
89
90
91
92
93
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
Coordonnee(1, 1));
Coordonnee(2, 1));
Coordonnee(3, 1));
Coordonnee(4, 1));
Coordonnee(5, 1));
Coordonnee(6, 1));
Coordonnee(7, 1));
Coordonnee(8, 1));
Coordonnee(10, 1));
Coordonnee(11, 1));
57
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
lc.ajouterTete(new
94
95
96
97
98
99
100
101
Coordonnee(12, 1));
Coordonnee(1, 2));
Coordonnee(2, 2));
Coordonnee(5, 2));
Coordonnee(7, 2));
Coordonnee(8, 2));
Coordonnee(10, 2));
Coordonnee(9, 2));
102
// on test avec une liste incomplette contenantdes case sale , si PiecePropre renvoie faux
assertFalse(p.piecePropre(lc));
103
104
105
}
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/∗∗
∗ test la methode correction de Piece
∗/
@Test
public void testCorrection() {
System.out.println("Test de la fonction Correction()");
// test avec une piece exploitable s ’ il n’y a pas eu de modification
Piece p = new Piece(new File("pieceTest.txt"));
int[][] pieceMauvaise = new int[5][5];
// contour
pieceMauvaise[0][0] = 1;
pieceMauvaise[1][0] = 1;
pieceMauvaise[2][0] = 1;
pieceMauvaise[3][0] = 1;
pieceMauvaise[4][0] = 1;
122
123
124
125
126
127
pieceMauvaise[0][4]
pieceMauvaise[1][4]
pieceMauvaise[2][4]
pieceMauvaise[3][4]
pieceMauvaise[4][4]
=
=
=
=
=
1;
1;
1;
1;
1;
128
129
130
131
pieceMauvaise[0][1] = 1;
pieceMauvaise[0][2] = 1;
pieceMauvaise[0][3] = 1;
132
133
134
135
pieceMauvaise[4][1] = 1;
pieceMauvaise[4][2] = 1;
pieceMauvaise[4][3] = 1;
136
137
138
139
// interrieur
140
141
142
143
pieceMauvaise[1][1] = 1;
pieceMauvaise[1][2] = 0;
pieceMauvaise[1][3] = 0;
144
145
146
147
pieceMauvaise[2][1] = 0;
pieceMauvaise[2][2] = 1;
pieceMauvaise[2][3] = 0;
148
149
150
151
pieceMauvaise[3][1] = 0;
pieceMauvaise[3][2] = 0;
pieceMauvaise[3][3] = 1;
152
153
int[][] resultat = new int[5][5];
58
154
// interrieur
155
156
157
158
resultat[1][1] = 1;
resultat[1][2] = 1;
resultat[1][3] = 1;
159
160
161
162
resultat[2][1] = 0;
resultat[2][2] = 1;
resultat[2][3] = 1;
163
164
165
166
resultat[3][1] = 0;
resultat[3][2] = 0;
resultat[3][3] = 1;
167
168
// contour
169
170
171
172
173
174
resultat[0][0]
resultat[1][0]
resultat[2][0]
resultat[3][0]
resultat[4][0]
=
=
=
=
=
1;
1;
1;
1;
1;
resultat[0][4]
resultat[1][4]
resultat[2][4]
resultat[3][4]
resultat[4][4]
=
=
=
=
=
1;
1;
1;
1;
1;
175
176
177
178
179
180
181
182
183
184
resultat[0][1] = 1;
resultat[0][2] = 1;
resultat[0][3] = 1;
185
186
187
188
resultat[4][1] = 1;
resultat[4][2] = 1;
resultat[4][3] = 1;
189
190
191
int[][] test = p.correction(pieceMauvaise, 5, 5);
192
193
194
195
196
197
198
199
200
201
202
boolean egale = true;
int i = 0;
int j = 0;
while (egale && i < 5) {
while (egale && j < 5) {
if (resultat[i][j] != test[i][j]) {
egale = false;
} else {
j++;
}
203
204
205
206
207
208
209
}
j = 0;
i++;
}
// test si la pièce a bien été
assertTrue(egale);
rectifié
210
211
212
213
p = new Piece(new File("pieceTest.txt"));
int[][] pieceBonne = new int[5][5];
59
214
215
216
217
218
219
// contour
pieceBonne[0][0]
pieceBonne[1][0]
pieceBonne[2][0]
pieceBonne[3][0]
pieceBonne[4][0]
=
=
=
=
=
1;
1;
1;
1;
1;
pieceBonne[0][4]
pieceBonne[1][4]
pieceBonne[2][4]
pieceBonne[3][4]
pieceBonne[4][4]
=
=
=
=
=
1;
1;
1;
1;
1;
220
221
222
223
224
225
226
pieceBonne[0][1] = 1;
pieceBonne[0][2] = 1;
pieceBonne[0][3] = 1;
227
228
229
230
pieceBonne[4][1] = 1;
pieceBonne[4][2] = 1;
pieceBonne[4][3] = 1;
231
232
233
234
235
236
// interrieur
237
238
pieceBonne[1][1] = 1;
pieceBonne[1][2] = 0;
pieceBonne[1][3] = 0;
239
240
241
242
pieceBonne[2][1] = 0;
pieceBonne[2][2] = 1;
pieceBonne[2][3] = 0;
243
244
245
246
pieceBonne[3][1] = 0;
pieceBonne[3][2] = 0;
pieceBonne[3][3] = 0;
test = p.correction(pieceBonne, 5, 5);
i = 0;
j = 0;
while (egale && i < 5) {
while (egale && j < 5) {
if (pieceBonne[i][j] != test[i][j]) {
egale = false;
} else {
j++;
}
247
248
249
250
251
252
253
254
255
256
257
258
259
260
}
j = 0;
i++;
261
262
263
}
// test si la pièce n’a pas été modifier
assertTrue(egale);
264
265
266
267
}
268
269
270
271
272
273
@Test
public void testtraduction() {
System.out.println("Test de la fonction traduction()");
/∗ Piece test :
000000001000
60
274
275
276
277
278
279
280
001101000011
100011000000
001000000001
001110000000
∗/
Piece p = new Piece(new File("pieceTest.txt"));
try {
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
// on test si le fichier traduit donne bien exactement la poèce voulu
assertTrue(p.getPiece(1, 1) == 0);
assertTrue(p.getPiece(2, 1) == 0);
assertTrue(p.getPiece(3, 1) == 0);
assertTrue(p.getPiece(4, 1) == 0);
assertTrue(p.getPiece(5, 1) == 0);
assertTrue(p.getPiece(6, 1) == 0);
assertTrue(p.getPiece(7, 1) == 0);
assertTrue(p.getPiece(8, 1) == 0);
assertTrue(p.getPiece(9, 1) == 1);
assertTrue(p.getPiece(10, 1) == 0);
assertTrue(p.getPiece(11, 1) == 0);
assertTrue(p.getPiece(12, 1) == 0);
assertTrue(p.getPiece(1, 2) == 0);
assertTrue(p.getPiece(2, 2) == 0);
assertTrue(p.getPiece(3, 2) == 1);
assertTrue(p.getPiece(4, 2) == 1);
assertTrue(p.getPiece(5, 2) == 0);
assertTrue(p.getPiece(6, 2) == 1);
assertTrue(p.getPiece(7, 2) == 0);
assertTrue(p.getPiece(8, 2) == 0);
assertTrue(p.getPiece(9, 2) == 0);
assertTrue(p.getPiece(10, 2) == 0);
assertTrue(p.getPiece(11, 2) == 1);
assertTrue(p.getPiece(12, 2) == 1);
assertTrue(p.getPiece(1, 3) == 1);
assertTrue(p.getPiece(2, 3) == 0);
assertTrue(p.getPiece(3, 3) == 0);
assertTrue(p.getPiece(4, 3) == 0);
assertTrue(p.getPiece(5, 3) == 1);
assertTrue(p.getPiece(6, 3) == 1);
assertTrue(p.getPiece(7, 3) == 0);
assertTrue(p.getPiece(8, 3) == 0);
assertTrue(p.getPiece(9, 3) == 0);
assertTrue(p.getPiece(10, 3) == 0);
assertTrue(p.getPiece(11, 3) == 0);
assertTrue(p.getPiece(12, 3) == 0);
assertTrue(p.getPiece(1, 4) == 0);
assertTrue(p.getPiece(2, 4) == 0);
assertTrue(p.getPiece(3, 4) == 1);
assertTrue(p.getPiece(4, 4) == 0);
assertTrue(p.getPiece(5, 4) == 0);
assertTrue(p.getPiece(6, 4) == 0);
assertTrue(p.getPiece(7, 4) == 0);
assertTrue(p.getPiece(8, 4) == 0);
assertTrue(p.getPiece(9, 4) == 0);
assertTrue(p.getPiece(10, 4) == 0);
assertTrue(p.getPiece(11, 4) == 0);
assertTrue(p.getPiece(12, 4) == 1);
assertTrue(p.getPiece(1, 5) == 0);
assertTrue(p.getPiece(2, 5) == 0);
assertTrue(p.getPiece(3, 5) == 1);
61
assertTrue(p.getPiece(4, 5) == 1);
assertTrue(p.getPiece(5, 5) == 1);
assertTrue(p.getPiece(6, 5) == 0);
assertTrue(p.getPiece(7, 5) == 0);
assertTrue(p.getPiece(8, 5) == 0);
assertTrue(p.getPiece(9, 5) == 0);
assertTrue(p.getPiece(10, 5) == 0);
assertTrue(p.getPiece(11, 5) == 0);
assertTrue(p.getPiece(12, 5) == 0);
334
335
336
337
338
339
340
341
342
343
} catch (Exception e) {
fail("exception générée dans le test ");
}
344
345
346
347
}
348
349
}
62
test de la classe « Menage »
Figure 8.5 – testMenage
Code JUnit de « testMenage »
1
public class MenageTest {
2
3
4
5
6
7
8
9
10
11
/∗∗
∗ Test la fonction menageR de la class Menage.
∗/
@Test
public void testMenageR() {
System.out.println("Test MenageR()");
// test si le menage s ’ arrete lorsque la pièce est propre
PageAcceuil.setEchelle(100);
PageAcceuil.setTempsMax(1000000000);
12
13
Menage m = new Menage(new File("pieceTest.txt"), 3, 0);
14
15
16
17
m.menageR();
boolean r = m.getP().piecePropre(m.getCoord());
assertTrue(r);
18
19
20
21
22
23
// test si le menage s ’ arrête lorsque le temps impartie s ’ est écoulé
// on accorde 3 déplacements
PageAcceuil.setEchelle(100);
PageAcceuil.setTempsMax(PageAcceuil.getEchelle() * 3);
24
25
m = new Menage(new File("pieceTest.txt"), 3, 0);
26
27
28
29
30
m.menageR();
r = m.getP().piecePropre(m.getCoord());
assertFalse(r);
31
32
33
34
// test que si le temps imparti est trop court , que l ’ on effectue pas le menage et donc que le robot n’a pas bougé
63
// on donne un temps trop court pour un déplacement
PageAcceuil.setEchelle(100);
PageAcceuil.setTempsMax(PageAcceuil.getEchelle() - 5);
35
36
37
38
m = new Menage(new File("pieceTest.txt"), 3, 0);
39
40
m.menageR();
r = m.getP().piecePropre(m.getCoord());
assertFalse(r);
assertTrue(m.getCoord().taille() == 1);
41
42
43
44
45
}
46
47
}
64