TER : ETERNITY 2
Transcription
TER : ETERNITY 2
TER : ETERNITY 2 d'AIGREMONT Louis SCIACCA Florian 1 Sommaire : 1) Introduction..........................................................................................................................p04 1. Historique.......................................................................................................................p04 2. Présentation du jeu.........................................................................................................p04 2) Modélisation du problème....................................................................................................p06 a) Les différents paramètres...............................................................................................p06 b) Arbres des possibilités....................................................................................................p07 3) Une première idée d'algorithme naïf....................................................................................p07 a) Présentation de l'algorithme...........................................................................................p07 b) NP-Complétude..............................................................................................................p08 4) Présentation des différentes familles d'algorithmes.............................................................p09 a) Le retour sur traces.........................................................................................................p09 b) Algorithmes Gloutons....................................................................................................p09 c) Méthodes diviser pour régner.........................................................................................p09 d) Heuristique.....................................................................................................................p10 e) Algorithmes randomisés ou probabilistes......................................................................p10 5) Les méthodes de retour sur traces........................................................................................p10 a) Les différents types de parcours.....................................................................................p10 1. Par rangée................................................................................................................p11 2. En diagonale............................................................................................................p12 3. En escargot...............................................................................................................p12 4. Parcours un sur deux d'abord...................................................................................p13 b) Complexité moyenne, au pire........................................................................................p14 c) Améliorations possibles.................................................................................................p15 1. Classement des pièces..............................................................................................p15 2. Recherche de plateau insolvable..............................................................................p15 d) Jeux d'essais....................................................................................................................p16 e) Conclusions....................................................................................................................p17 6) Branch and bound.................................................................................................................p17 a) Présentation de la méthode.............................................................................................p17 b) Adaptation pour Eternity 2 ............................................................................................p17 2 1. Pièce de « poids minimal ».......................................................................................p17 2. Combinatoire des éléments restants. .......................................................................p18 c) Résultats, Conclusion.....................................................................................................p18 7) Ouvertures du problème.......................................................................................................p19 a) Une méthode diviser pour régner...................................................................................p19 1. Principe....................................................................................................................p19 2. Avantages.................................................................................................................p19 b) Le gradient bruité...........................................................................................................p20 1. Principe de l'algorithme............................................................................................p20 2. Problèmes rencontrés................................................................................................p20 8) Apports du TER....................................................................................................................p21 Références........................................................................................................................................p21 3 1) Introduction a) Historique Eternity II a été lancé le 28 juillet 2007, dans vingt pays, avec la promesse de deux millions de dollars pour le premier qui le résoudra. Ceci n'est pas le premier puzzle du genre, puisqu'il existe une première version d' Eternity sorti en 2000 en Angleterre. Ce puzzle est composé 205 pièces devant formé un dodécagone, dont voici une solution : Comme on peut le voir le style de puzzle est particulier, mêlant jeu de réflexion et puzzle ludique, derrière cela se cache un vrai problème algorithmique qui mérite et demande une étude approfondie. b) Présentation du jeu. Eternity II est un jeu composé : – d'un plateau de jeu carré représentant une grille de 16 par 16. 4 – de 256 pièces carrées toutes différentes ayant chacune un motif sur chaque bord (donc quatre motifs par carré). Étant carré il n'y a aucune contrainte pour le sens de placement de la pièce, ce qui donne la possibilité de la disposer de quatre manières différentes : Le but étant de placer les 256 pièces sur le plateau de manière à ce que chaque motif coïncide avec celui d'à coté : Nous pouvons aussi observer un motif spécifique pour la bordure (gris uni dans les illustrations), ainsi nous pouvons classer les pièces en 3 catégories : 1. les coins 2. les bords 3. les pièces centrales. Ainsi un exemple de solution sur un tableau de quatre par quatre : 5 2) Modélisation du problème. a) Les différents paramètres. Au vu des différents éléments qui composent Eternity II et de la seul règle qui le régisse, les données à prendre en compte sont : – le nombre de pièces N ou n*n qui doivent remplir la grille carré. – le nombre de motifs différents K pouvant être séparer en deux sous catégories : – les p motifs de bords. – les k motifs centraux. Le problème dépend fortement du nombre de motifs, donc s'il y a peu de couleurs les combinaisons gagnantes seront nombreuses, et les chances d'avoir des pièces identiques augmentées. En revanche, s'il y en a beaucoup de couleurs par rapport à la dimension de la grille, la solution deviendra plus simple à trouver, puisque plus dirigée. Nous pouvons voir le problème de plusieurs façons différentes : – par rapport au plateau : on peut poser (a) pièces sur la case (i). – par rapport au pièces : la pièce (n) peut aller sur les cases 1, 5, 75, 198... – un mélange des deux solutions au-dessus, prenant en compte les cases possibles pour chaque pièce et les pièces possibles pour chaque case. – par rapport à un plateau déjà rempli : toutes les pièces étant posées sur le plateau, on modifie son état (rotation d'une pièce, échange de deux pièces, de groupes de pièces). 6 b) Arbres des possibilités. Un arbre des possibilités peut être construit par rapport à notre choix d'interprétation se définissant selon plusieurs paramètres. Les noeuds sont successivement une case et une pièce dans une position (position initiale puis rotation de 90° à chaque fois pour avoir toute les possibilités d'une pièce). Tandis que les feuilles représentent la dernière pièce placée. La relation père fils dépend du noeud, de ce fait, si le noeud représente une case il sera le père et le fils d'une pièce ou du plateau vierge. À l'inverse, s'il représente une pièce, il sera le père et le fils d'une case. A noter que dans une même branche on ne pourra en aucun cas trouver deux fois la même pièces ou la même case. De plus, la racine représente le plateau de jeu vierge. Cet arbre ne représente pas seulement les possibilités de plateau pouvant être crées mais aussi l'ordre de parcours. Ainsi certaines feuilles donnent le même résultat car le placement des pièces ne s'est pas fait de manière identique. Cet arbre peut être simplifié en choisissant un ordre fixe et arbitraire de parcours, ce qui a pour effet d'annuler le choix des cases dans celui-ci. 3) Une première idée d'algorithme naïf. a) Présentation de l'algorithme. L'algorithme naïf est celui qui va parcourir l'arbre en profondeur. A chaque fois qu'il atteint une feuille, soit la solution est bonne, soit il recule d'un noeud pour rejoindre la feuille la plus proche, Dans le pire des cas nous parcourons tout l'arbre jusqu'à la dernière feuille, ce qui revient donc à une complexité en N !∗4 N : O( k N ). 7 Nous savons que chaque pièce peut être placée de quatre manières différentes, nous aurons donc 4*N possibilités pour placer la première pièce. Pour ce qui est de la deuxième pièce, nous aurons 4∗ N −1 et ainsi de suite. Une simple factorisation permet de trouver la formule énoncée plus haut. Nous pouvons calculer le nombre de plateaux possibles de manière assez simple, en plaçant toutes les pièces de toutes les manières possibles, pour Eternity II la formule donne : Soit approximativement 1,15*10^662 plateau possibles [1]! Cet algorithme prendrait un temps considérable pour résoudre le problème, il n'est pas nécessaire de le voir plus en détail, néanmoins cela laisse envisager que le problème est NP-Difficile. b) NP-Complétude. Pour prouver qu'un tel problème est NP-Difficile, nous allons démontrer qu'il peut se rapporter à un problème lui même NP-Complet : le Tetravex. (La démonstration a été faite par Takenaga et Walsh [2]). Présentation du Tetravex : Le Tetravex est un jeu de réflexion de type puzzle lui aussi. Tout comme dans Eternity II, on commence avec une grille de taille n*n vierge, et n*n pièces carrés, ayant chacun un numéro sur chaque bord (donc quatre numéros par pièce). Le but est de placer ces pièces sur la grille, en faisant en sorte que le numéro d'un bord soit le même que celui de la pièce adjacente. Chaque face de chaque pièce est donc posée à coté d'une face de même nombre. Le jeu se termine quand la grille est remplie avec toutes les pièces, correctement placées. Nous pouvons inclure le Tetravex à l'intérieur d'un problème de type Eternity II. Pour un Tetravex de taille n*n nous prenons un type Eternity de taille n1∗ n1 , avec k=10 (le nombre de 8 motifs centraux). Il faudra prendre en compte le fait que la position de chaque pièce devant être placée (pas de rotation pour les pièces) a été fixé, au préalable. A ce moment là, nous avons deux problèmes dans Eternity II : qui sont résoudre le Tetravex et former une couronne qui aille autour. Le Tetravex peut donc être considéré comme un sous-problème d'Eternity II, comme il a été prouvé que le Tetravex est NP-complet, Eternity II l'est également si la couronne ne simplifie pas le calcul du Tetravex en contraignant son bord, ce qui semble une hypothèse raisonnable, malheureusement le temps pour faire une démonstration rigoureuse n'a pas été suffisant. 4) Présentation des différentes familles d'algorithmes. Avec un problème de cette envergure, nous allons essayer de trouver un algorithme parmi les classes que nous connaissons, afin de réussir à baisser le temps ou même à le ramener à un temps polynomial si cela s'avère possible. Pour cela revoyons ces différentes classes. a) Le retour sur traces. Le retour sur trace consiste à avancer jusqu'à arriver à un blocage de l'algorithme qui revient alors légèrement en arrière afin d'en sortir. Il s'applique souvent au problème de satisfaction de contrainte (CSP), comme ordonnancement(trafic ferroviaire), affectation de ressources (emploi du temps), problèmes d'optimisation (routage réseaux). Mais aussi aux jeux qui se rapprochent ou sont des CSP. b) Algorithmes Gloutons. Les algorithmes qui résolvent les problèmes d’optimisation parcourent en général une série d’étapes, au cours desquelles ils sont confrontés à un ensemble d’options. Pour de nombreux problèmes d’optimisation la programmation dynamique est une approche trop lourde pour déterminer les meilleures solutions ; d’autres algorithmes plus simples et efficaces y arriveront. Un algorithme glouton fait toujours le choix qui semble le meilleur sur le moment. Autrement dit, il fait un choix optimal localement, dans l’espoir que ce choix mènera à la solution optimale globalement. Les algorithmes gloutons n’aboutissent pas toujours à des solutions optimales, mais la méthode gloutonne est très puissante et fonctionne correctement pour des problèmes variés. c) Méthodes diviser pour régner. Nombres d’algorithmes ont une structure récursive : pour résoudre un problème donné, ils s’appellent eux-mêmes récursivement une ou plusieurs fois sur des problèmes similaires, mais de tailles moindres, résolvent les sous-problèmes de manière récursive puis combinent les résultats pour trouver une solution au problème initial. Le paradigme « diviser pour régner » donne lieu à trois étapes à chaque niveau de récursivité : Diviser : le problème en un certain nombre de sous-problèmes ; Régner : sur les sous-problèmes en les résolvant récursivement ou, si la taille d’un sous-problème 9 est assez réduite, le résoudre directement. Combiner : les solutions des sous-problèmes en une solution complète du problème initial. d) Heuristique. En optimisation combinatoire, Théorie des graphes et théorie de la complexité, une heuristique est un algorithme qui fournit rapidement (en temps polynomial) une solution réalisable, pas nécessairement optimale, pour un problème d'optimisation NP-Difficile. Une heuristique, où méthode approximative, est donc le contraire d'un algorithme exact qui trouve une solution optimale pour un problème donné. L'intérêt de l'heuristique étant que pour les problèmes NPdifficiles, les algorithmes exacts connus sont tous de complexité exponentielle et donc sans aucun intérêt en pratique. On utilise presque systématiquement une heuristique pour obtenir une première solution réalisable dans un processus de résolution exacte. e) Algorithmes randomisés, ou probabilistes. Les algorithmes randomisés sont des algorithmes qui effectuent des choix aléatoires au cours de leur déroulement. Contrairement aux algorithmes probabilistes (dits de Monte Carlo) les algorithmes randomisés (encore appelés algorithmes de Las Vegas) fournissent la solution exacte d'un problème déterministe et ne font aucune hypothèse statistique sur les données traitées. Seule leur complexité dépend des choix aléatoires effectués et s'analyse en moyenne. En conférant aux situations défavorables un poids statistique négligeable, la randomisation conduit à des algorithmes simples et efficaces, notamment en géométrie. 5) Les méthodes de retour sur traces. Le principe est d'avancer pas à pas, on place une pièce après l'autre dans un certain ordre jusqu'à bloquer (plus de pièce compatible avec la case où l'on se trouve), on recule alors d'un cran, en tournant ou en remplaçant la dernière pièce posée à la recherche d'une autre solution jusqu'à finir le plateau. a) Les différents types de parcours. Après avoir défini l'algorithme, il faut maintenant choisir dans quel ordre nous devons remplir le plateau. Mais d'abord il faut se demander si l'ordre influe sur la vitesse de résolution. Pour pouvoir répondre à cette question, il faut savoir que l'ordre de parcours a un impact sur l'ordre des tests qu'il faudra faire sur les pièces, et les types de ces tests. Nous allons définir cinq types de test qui peuvent être appliqués : – 0-test, aucune contrainte, on peut placer n'importe qu'elle pièce. 10 – 1-test, la pièce doit contenir une couleur définie. – 2-test, la pièce doit contenir deux couleurs dans un certain ordre. – 3-test, la pièce doit contenir trois couleurs. – 4-test, la pièce doit correspondre exactement. Le nombre total de tests étant constant car les contraintes peuvent être définies par les arêtes (contact entre deux pièces ou entre une pièce et le bord), ce nombre est donc 2∗n² 2∗n . Le parcours définit aussi ce que l'on appellera la promiscuité des pièces, c'est à dire depuis combien de temps les pièces qui entourent une pièce donnée ont été placées. Cette donnée est utile, surtout pour ce type d'algorithmes car si nous n'avons plus de pièces pouvant rentrer à un emplacement donné, le programme retournera en arrière pour changer la pièce placée juste avant, si cette pièce « touche » la suivante, elle aura plus de chance de débloquer le problème. Nous définissons donc un temps t négatif qui indique depuis combien d'itérations certaines pièces ont été placées. Dans tous les types de parcours nous partons d'un coin, cela permet de partir d'une pièce qui ne sera pas modifiée. En effet, les coins ont un arrangement de 4! mais l'ordre n'a pas d'importance au vu de la forme du plateau (carré), nous pouvons donc fixer le premier coin et chercher un arrangement pour les autres. 1. Parcours par rangée. Le principe est de remplir ligne après ligne comme indiqué ci-dessous : Avantage : très simple à mettre en oeuvre, constitué uniquement de 2-test, 3-test et 4-test. Apparition des tests : les 3-tests apparaissent à la fin de chaque ligne, donc tous les n case, ainsi que lors du remplissage de la dernière ligne, jusqu'à la dernière case qui est un 4-test, le reste étant des 2-tests. Promiscuité : chaque pièce est liée à sa précédente par la gauche sauf celle qui commence une ligne. Elles sont aussi liées par au-dessus avec la pièce placée au temps t=-n. Pour améliorer la promiscuité en gardant le même système de remplissage, nous pouvons utiliser un parcours « en serpent » : 11 La nouvelle promiscuité : ici c'est le lien avec au-dessus qui est modifié, quand nous commençons une ligne le temps par rapport à la pièce d'au-dessus est de -1 et il croît jusqu'à la dernière case de cette ligne où t=-n. Il y a ainsi un certain équilibre dans la mesure où à la ligne suivante la première pièce sera liée avec cette dernière et sera donc de temps t=-1. 2. Parcours en diagonale Le principe est de remplir en diagonale de haut en bas et de gauche à droite. Apparition des tests : Nous pouvons voir ici le tableau rempli par les tests effectués, en partant du haut gauche comme dans l'ordre de parcours, nous avons d'abord rempli un carré de taille n-1 avec des 2-tests. Quant aux dernières lignes, elles sont constituées de 3-test sauf le dernier coin qui est un 4-test. Cela provient du fait que nous créons d'abord un triangle qui s'agrandit, ainsi les tests se font au-dessus et à gauche. Par après, nous fermons le deuxième triangle pour former le carré, les bords de ce triangle ont donc une contrainte de plus. Promiscuité : Ici les pièces sont liées avec celle d'au-dessus et celle de gauche, donc le parcours ne lie une pièce avec la précédente qu'au changement de ligne, nous aurons une plus forte promiscuité au niveau des coins de départ et d'arrivée mais elle baissera au niveau de la diagonale. 3. Parcours en escargots. 12 Le principe est de remplir du bord vers le centre. Utilité : Nous créons la bordure en premier, ce qui peut s'avérer utile puisqu'elle permet de réduire le nombre de couleurs total. Apparition des tests : De cette manière l'ordre d'apparition des 3-tests est le meilleur que nous ayons trouvé. En effet, ils apparaissent d'abord une fois pour n puis deux fois pour n-1, deux fois pour n-2 jusqu'à arriver à une fois pour 1. Promiscuité : dans ce parcours, une pièce est toujours liée à sa précédente. Par contre, les autres liens sont beaucoup plus éloignés, la première pièce à avoir plus d'une pièce à coté est celle qui ferme la bordure. Elle est liée à la première pièce placée sur le plateau donc un t=-4n. Par la suite, ce type de promiscuité décroît jusqu'à la dernière pièce qui a t=-1, t=-3, t=-5 et t=-7 pour voisins. 4. Parcours « un sur deux d'abord ». Le principe est de remplir une case sur deux de manière à former un damier, puis nous terminons le remplissage en comblant les trous. Utilité : ce parcours est instinctivement le pire envisageable, il a été utilisé pour une batterie de tests visant à conjecturer sur l'importance de l'ordre du parcours. 13 Apparitions des tests : la première partie de remplissage (la formation du damier) contient de très petits tests. Dans le carré central de n−1² il n'y a pas de test. La seconde partie est uniquement composée de 4-tests. Promiscuité : Avec cette approche la promiscuité est très faible, dans la première moitié du remplissage il n'y en a pas et ensuite les pièces sont faiblement liées (il y a une distance d'environ N/2). b) Complexité moyenne, au pire. Tous cela n'est que basé sur des impressions qui ne permettent pas d'affirmer qu'une méthode sera meilleure qu'une autre. Nous allons donc nous pencher sur la complexité des algorithmes : Nous pouvons voir la complexité de la recherche d'une pièce par rapport à son nombre de contraintes : – 0-test, en O(1) nous pouvons prendre la 1er pièce disponible. – 1-test,en O( 4 N ) nous parcourons une fois la liste en testant chaque pièce dans toutes les positions possibles. – 2-test, 3-test et 4-test ont un coût de plus en plus élevé mais il n'est pas fixe (dépend du nombre de pièces qui ont la première couleur, puis du nombre de pièce qui ont les deux premières couleurs et ainsi de suite). Néanmoins les 4^N unités d'informations fournis par le 1-test doivent être suffisante pour réaliser l'ensemble des tests. On peut donc estimer coup les coûts sont asymptotiquement identiques. Pour la formule nous avons : – Ci complexité de la recherche de pièce pour la position i. – Cr complexité de ce qui reste à chercher. – Ai le nombre de pièces qui peuvent se placer en position i. Nous avons donc : A1∗C1 A2∗C2 A3∗C3... AN ∗CN ... Nous utilisons ici une simplification de la formule de complexité, en disant que la complexité à une position donnée (Ci) est toujours la même ainsi que le nombre de pièces Ai qui lui est relié. Ceci n'étant pas vrai car à chaque retour en arrière quand nous changeons la pièce en i-1, le calcul de Ci se trouve modifié ainsi que le nombre de pièces pouvant y être placées. Nous avons la formule non simplifié pour un tableau de taille 4. A1∗ C1i A2i∗ C2j A3j∗ C3k A4k∗C4 Ici nous pouvons voir que le nombre de pièces Ai à une grande importance, surtout au début de l'algorithme, plus il sera grand plus le temps d'exécution sera long. Le nombre de pièces pouvant se placer en une certaine position dépend des contraintes sur cette position : 14 Ai =N −i−1 – 0-test, toutes les pièces restantes peuvent être placées – 1-test, Ai vaut le nombre de pièces ayant la couleur demandée – 4-test, Ai vaut 1 car il n'y a pas deux pièces identiques. c) Améliorations possibles. Nous avons réfléchi à l'amélioration de la vitesse de résolution pour ce type d'algorithmes : 1. Classement des pièces. Trier les pièces par motif, en créant K tableaux contenant chacun les pièces se rapportant à sa couleur (les pièces seraient donc recensées quatre fois chacune).L'utilité de cela est de ramener la recherche d'une couleur à un temps en O(K), la recherche de pièce serait donc accélérée (on peut estimer pouvoir ramener ce coût à O(1) à l'aide d'une table de hachage). 2. Détection de plateau insolvable. L'idée est de trouver quand un plateau n'est plus solvable, le plus tôt possible, avec des règles simples, il faut donc définir à quel moment il devient insolvable: – il manque une couleur : nous avons besoin d'une couleur que nous n'avons plus – il manque des pièces : Pour réaliser une telle études, il faut connaître plusieurs paramètres : – le nombre de pièces dans chaque motif : M. – le nombre de fois que le motif apparaît dans la liste des pièces : D. – le nombre de fois que le motif apparaît dans la frontière (la frontière étant l'ensemble des cases vides n'ayant pas de contraintes nulles, c'est à dire des cases au moins 1-test) : Front . Nous pouvons aussi détailler, le nombre de pièces : – qui ont trois fois le motif : A – qui ont deux fois le motif côte à côte : B1 – – qui ont deux fois le motif l'un en face de l'autre : B2 qui ont une seul fois le motif : C. Pareil pour la couronne : – nombre de fois qu'un motif apparaît deux fois en formant un angle : Ang – nombre de fois que deux motif se suivent : Suiv. 15 Ainsi nous avons différentes formules que nous pouvons mettre en place : – Un test pour savoir s'il reste assez de pièces pour remplir la frontière: M ≥Front−ang – Un test pour savoir s'il y a assez de pièces pour remplir les angles : A B1≥Ang – Un test pour vérifier qu'il n'y a pas trop de motifs pour le nombre de pièces restantes : Cela implique le nombre maximal de motifs dans le nombre minimal de pièces si M Ang−Front4 alors D−Front≤2∗Suiv3∗ M Ang− Front−42∗4 Ang−Front sinon D−Front≤2∗suiv2∗ M Ang− Front d) Jeux d'essais. Nous avons ici huit jeux d'essais basés sur un plateau 4*4 de 3 couleurs, montrant combien d'opérations élémentaires (poser/tourner/enlever une pièce) le programme à effectué pour parvenir à la solution. Les jeux d'essais ont été générés aléatoirement à l'aide du programme, et résolues à l'aide de ce même programme, avec différents modes de remplissage. Jeu 1 Jeu 2 Jeu 3 Serpent Diagonale Un sur deux Escargot Ligne Jeu 4 98 164 69 416 244 52 28800 32896 30045 428 162 66 344 416 656 Jeu 5 Jeu 6 Jeu 7 Jeu 8 Moyenne Moyenne sans jeu 7 340 16 22 1098 0 225,88 101,29 282 119 432 440 214 274,88 220,71 45813 43652 47120 33615 34097 37004,75 32618 387 38 24 264 22 173,88 157,86 280 43 65 439 58 287,63 257,71 e) Conclusions. Les jeux d'essai nous montrent l'importance de la promiscuité ainsi que de l'ordre des tests, de ce fait, si nous ne prenons pas compte du jeu 7, nous voyons que le serpent à la meilleure moyenne, sinon c'est l'escargot qui devient le meilleur. Ainsi le plus performant est celui à la meilleure promiscuité ou celui qui a les tests les mieux répartis. Des tests plus poussés permettraient de déterminer lequel de ces deux caractéristiques est la plus importante, et psourquoi. Note: les résultats du jeu 7 pour l'ordre « serpent » sont exotiques, c'est pourquoi nous les avons mis en marges. L'agencement des pièces au départ devait être très mauvais pour ce parcours. Sur huit jeux d'essais obtenir un tel agencement est vraiment surprenant. 6) Branch and bound. a) Présentation de la méthode. 16 La stratégie de Branch and Bound est une variante du Backtracking mais qui l'améliore substantiellement. Le terme Branch and Bound est appliqué la plus part du temps pour résoudre les problèmes d'optimisations. La technique de BB est un arbre de solutions où chaque branche mène à une possible solution ultérieure à l'état où nous nous trouvons. La caractéristique principale de cette technique consiste dans le fait que l'algorithme se propose de trouver dans quelle branche les solutions ont le plus de chance d'être trouvées pour ne pas continuer inutilement. Le BB dans sa version plus simple peut suivre, à différence du backtracking, un parcours en largeur (Last In Last Out), en profondeur (First In First Out) ou utiliser le calcul des fonctions de coût pour choisir le noeud le plus prometteur. b) Adaptation pour Eternity 2 Comme indiqué juste en haut la méthode BB est utilisée la plupart du temps pour des problèmes d'optimisations, ici le problème n'en est pas un, nous avons donc du l'adapter. 1. Pièce de « poids minimal » et place de « poids minimal » ● Explication de la méthode Cette méthode vient du calcul de la complexité pour le backtracking, l'idée étant de minimiser les Ai le plus possible, en choisissant toujours la case où le nombre de pièces que l'on peut placer est le plus petit, et en plaçant la pièce qui aurait pu aller sur le moins de cases. Avec cette méthode, on augmente les chances de placer une pièce juste (moins de choix donc moins de chance de se tromper), tout en gardant la combinatoire la plus élevée possible dans le bas de l'arbre, donc une forte chance de conserver une solution. Il s'agit donc choisir la meilleure case et d'y placer la meilleure pièce (cela fait penser à un algorithme glouton). Il faut donc définir une façon de départager les branches afin de choisir la plus prometteuse. Remarque : Une version différente et à examiner serait de choisir la meilleure pièce, puis de la placer sur la meilleure case. Les deux approchent ne produiront pas le même résultats. ● Mise en oeuvre Pour mettre cette méthode en oeuvre, nous avons pensé mettre un poids sur chaque case du plateau, on va donc voir pour cela l'initialisation de ces poids en fonction des cases puis la méthode de propagation des informations lors de la pose d'une pièce. L'initialisation : 17 Dans un premier temps, nous pouvons définir trois zones sur le plateau. Ces zones étant les coins (4 cases), la bordure ((n-1)*4 cases), le plateau central ( (n-2)² cases). Chacune des cases de chaque zone se voit attribuer le poids du nombre de cases de sa zone, ce qui correspond aussi au nombre de pièces que l'on peut poser sur la dite case. La propagation : Lors de la pose d'une pièce, il faut voir les conséquences que cela a pour les poids des cases encore vides. Il y a ensuite les effets sur l'entourage direct de la case, sur une zone plus ou moins grande autour de la case, ses voisines ont leurs poids modifiés. La question est de savoir jusqu'où calculer ces changements. Dans un premier temps, les quatre cases les plus proches (nord, sud, est, ouest). Ensuite, nous pouvons envisager de calculer par « matching » (calculer en fonctions des possibilités des deux pièces voisines) les quatre cases se trouvant en diagonale de la case que l'on vient de remplir. MATCH 1 VOISIN NORD MATCH 2 VOISIN OUEST PIÈCE VOISIN EST MATCH 3 VOISIN SUD MATCH 4 Il faut ensuite savoir que le coût est important surtout pour le « matching » (pour calculer match1, il faudrait tester toutes les pièces pouvant y aller en fonction de toutes celles du voisin nord et du voisin ouest), le coût d'une telle évaluation serait certainement supérieur au gain apporté par ce calcul. Une idée pour limiter au maximum le coût de l'opération est de retenir pour chaque pièce la liste des cases sur lesquelles elle peut être posée, et vice versa. Quand on pose une pièce P sur une case C, il suffit de baisser le poids de toutes les cases qui pouvaient accueillir P et de vérifier pour les quatre voisins directs quelles sont les pièces qui peuvent toujours convenir. 2. Combinatoire des éléments restants. L'idée est en fait basée sur la deuxième amélioration du backtracking, qui indique à chaque moment (à chaque noeud) si le jeu est encore potentiellement réalisable avec les pièces qu'il reste. Une solution serait alors de poser une pièce qui à le plus de chance d'aboutir à ce cas de figure. La difficulté vient alors du fait de déterminer assez tôt cette possibilité. c) Résultats, Conclusion. Nous avons manqué de temps pour pouvoir réaliser des jeux d'essai sur cet algorithme, nous ne pouvons donc dire s'il est meilleur qu'un autre uniquement en se basant sur la théorie. Seulement nous pouvons aussi prévoir, en fonction des résultats des jeux d'essai pour le retour sur trace, que la perte de promiscuité causé par le type de sélection des cases peut avoir une conséquence désastreuse sur le déroulement de l'algorithme. Ainsi il conviendrait de produire des jeux d'essai pour les confronter afin de trouver la meilleure méthode. 18 7) Conclusion, ouverture du problème. Nous avons détaillé précédemment différentes façons pour résoudre Eternity II basé sur une méthode de retour sur traces, et nous avons essayé d'y ajouter plusieurs heuristiques pour améliorer au mieux la vitesse d'exécution. Nous avons d'abord étudié les différents parcours de type « retour sur trace » qui nous ont permis de comprendre l'importance de la promiscuité. De même, grâce au calcul de la complexité nous avons observé l'influence du choix de la cases à remplir en priorité, ceci nous amenant à la méthode du Branch and Bound dans la mesure où il optimise ce choix. Malgré cela, la perte de promiscuité de cette méthode peut la rendre moins efficace qu'une autre même si sa complexité au pire est meilleure. Trois programmes différents ont étés réalisés en C : – Le premier est un simple générateur de permutations, il génère dans un fichier un ordre de parcours aléatoire, de longueur précisé en argument. – Le second est un générateur de plateaux aléatoires utilisé pour réaliser les jeux d'essais. Il prend en argument la taille du plateau, le nombre de couleurs et un entier qui indique si le jeu doit être solvable ou non. – Enfin le dernier programme prend en entrée un fichier de parcours, et un jeu d'essai et cherche une solution en temps en réel du problème posé. Une interface graphique (Glut) a été codée de manière à mieux suivre le déroulement de l'algorithme. Le temps imparti pour ce projet été bien trop court pour analyser en profondeur l'ensemble du problème. Ainsi plusieurs algorithmes n'ont pas pu être approfondi tel que : a) Une méthode « diviser pour régner ». 1. Principe de l'algorithme. Diviser : séparer le problème en des sous-ensembles de quatre pièces formant elle même une pièce de taille 2*2. Régner : créer l'ensemble des n /2 ² pièces qui puissent potentiellement résoudre le plateau, donc en ayant quatre coins et 4∗n−4/2 bords. Combiner : réitérer la méthode du régner jusqu'à avoir une pièce de la taille du plateau. 2. Avantages. Le principe est d'augmenter le nombre de couleurs, en créant des pièces ayant un coté de deux motifs, nous multiplions le nombre de motifs par lui même (k²). Le but étant de trouver au fur et à mesure des K-motifs qui ne peuvent être reproduit et de les mémoriser pour augmenter le nombre de règles et ainsi réduire l'arbre. 19 Le point important est l'augmentation rapide du nombre de motifs, à la deuxième itération nous avons k 4 motifs différents ce qui a de grandes chances de ne pas comporter de solution. On peut envisager une solution qui le combinerait avec du chaînage arrière : créer les pièces 2*2 puis utiliser un algorithme de backtracking pour terminer le plateau sans former des pièces plus grandes. Néanmoins créer un jeu de pièce de taille supérieur, pour au final, se rendre compte qu'il est impossible de régner sur le plateau est une perte importante de temps. Il semble alors logique de chercher à reproduire lors de la création de pièce, les motifs dont nous avons besoins. Une telle méthode se rapproche dangereusement d'un backtracking classique, c'est pourquoi nous n'avons pas étudiés d'avantage cette théorie, même si elle peut présenter certains avantages. b) Le gradient bruité. 1. Principe de l'algorithme. L'idée est de placer aléatoirement toutes les pièces sur le plateau puis de calculer un score représentant la différence entre ce jeu et la solution finale. Ensuite, il faut choisir le changement (permutation de deux pièces, rotation d'une pièces) qui donne le meilleur score suivant. Le bruit serait généré par une pourcentage de chance que l'algorithme choisisse un changement aléatoire plutôt que celui qui améliore le score. Cela donnerait un algorithme : Placer aléatoirement les pièces Calculer le score tant que le score n'est pas maximum choix aléatoire entre recherche du meilleur changement possible changement aléatoire procéder au changement. Calculer le score Fin tant que. 2. Problèmes rencontrés. D'abord la méthode de calcul du score n'est pas évidente, car nous n'avons aucune idée du nombre de pièces placées correctement. Nous pourrions définir un nombre comme le nombre de pièces bien liées, ce qui amènerait le score maximal à 4*N (toutes les pièces sont bien liées avec leur quatre voisines), mais il existe peut être un meilleur calcul qui prendrait plus de paramètres en compte le respect des zones coins, bordure, centre ou encore le nombre de pièces bien placées pour chaque motif. 20 Il y a aussi un risque de s'enfoncer dans des maximums locaux, un ensemble de quatre pièces bien placées entre elles mais qui ne font pas parties de la solution optimale. Ceci doit être évité par le bruit donc le pourcentage de chance de choisir la permutation aléatoire doit être assez élevée. De la même manière, cet algorithme devrait être lancé pendant un certain temps puis relancé pour placer au départ les pièces dans un ordre différent. Les changements possibles sont aussi à définir, par exemple, donner la possibilité de déplacer un groupe de pièces qui sont déjà bien liées entre elles. Cette méthode, proche des méthodes utilisées par l'intelligence artificielle, semble prometteuse, si les règles sont bien définies, alors les chances d'obtenir rapidement une solution viable sont meilleures qu'avec un backtracking classique. La difficulté vient bien entendu de la définition de ses règles. 8) Apports du TER. Il fut très intéressant de travailler sur ce projet qui nous à permis de nous ouvrir à de nouvelles façons de prendre en main un problème. De plus, la perspective de gagner une somme conséquente sur une idée géniale, ou sur un coup de chance, nous a fortement motivé. De surcroît, ce sujet nous a donné envie de comprendre et d'approfondir les problèmes algorithmiques. Références : [1] http://en.wikipedia.org/wiki/Eternity_II_puzzle [2] Y. Takenaga, T. Walsh. Tetravex is NP-complete in information processing letters 99, 2006, pp.171-174 21