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 n1∗ n1 , 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−Front4
alors
D−Front≤2∗Suiv3∗ M Ang− Front−42∗4 Ang−Front
sinon
D−Front≤2∗suiv2∗ 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

Documents pareils