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