J'ai développé une IA de 2048 en utilisant expectimax au lieu de la recherche minimax utilisée par l'algorithme d'@ovolve. L'IA effectue simplement une maximisation sur tous les mouvements possibles, suivie d'une espérance sur toutes les apparitions de tuiles possibles (pondérée par la probabilité des tuiles, c'est-à-dire 10% pour un 4 et 90% pour un 2). Pour autant que je sache, il n'est pas possible d'élaguer l'optimisation expectimax (sauf pour supprimer les branches qui sont excessivement improbables), et l'algorithme utilisé est donc une recherche par force brute soigneusement optimisée.
Performance
Dans sa configuration par défaut (profondeur de recherche maximale de 8), l'IA met entre 10 et 200 ms pour exécuter un coup, en fonction de la complexité de la position sur le plateau. Lors des tests, l'IA atteint un taux de déplacement moyen de 5 à 10 coups par seconde au cours d'une partie entière. Si la profondeur de recherche est limitée à 6 coups, l'IA peut facilement exécuter plus de 20 coups par seconde, ce qui donne lieu à des résultats très intéressants. regard intéressant .
Pour évaluer les performances de l'IA, je l'ai fait tourner 100 fois (connecté au jeu par navigateur via une télécommande). Pour chaque tuile, voici les proportions de jeux dans lesquels cette tuile a été atteinte au moins une fois :
2048: 100%
4096: 100%
8192: 100%
16384: 94%
32768: 36%
Le score minimum sur l'ensemble des runs est de 124024 ; le score maximum atteint est de 794076. Le score médian est de 387222. L'IA n'a jamais échoué à obtenir la tuile 2048 (elle n'a donc jamais perdu la partie, même une fois sur 100 parties) ; en fait, elle a obtenu le score le plus élevé. 8192 tuile au moins une fois dans chaque course !
Voici la capture d'écran de la meilleure course :
Cette partie a nécessité 27830 coups en 96 minutes, soit une moyenne de 4,8 coups par seconde.
Mise en œuvre
Mon approche consiste à encoder l'ensemble du tableau (16 entrées) sous la forme d'un seul entier de 64 bits (où les tuiles sont les nybbles, c'est-à-dire des morceaux de 4 bits). Sur une machine 64 bits, cela permet de faire passer le tableau entier dans un seul registre machine.
Les opérations de décalage de bits sont utilisées pour extraire des lignes et des colonnes individuelles. Une seule ligne ou colonne est une quantité de 16 bits, de sorte qu'une table de taille 65536 peut coder des transformations qui opèrent sur une seule ligne ou colonne. Par exemple, les déplacements sont implémentés sous la forme de 4 consultations d'une "table d'effet de déplacement" précalculée qui décrit comment chaque déplacement affecte une seule ligne ou colonne (par exemple, la table "déplacement vers la droite" contient l'entrée "1122 -> 0023" décrivant comment la ligne [2,2,4,4] devient la ligne [0,0,4,8] lorsqu'elle est déplacée vers la droite).
La notation est également effectuée à l'aide d'une table de consultation. Les tableaux contiennent des scores heuristiques calculés sur toutes les lignes/colonnes possibles, et le score résultant pour une planche est simplement la somme des valeurs du tableau pour chaque ligne et chaque colonne.
Cette représentation du plateau, ainsi que l'approche de consultation des tables pour les mouvements et les scores, permet à l'IA de rechercher un très grand nombre d'états de jeu dans un court laps de temps (plus de 10 000 000 d'états de jeu par seconde sur un cœur de mon ordinateur portable de mi-2011).
La recherche expectimax elle-même est codée comme une recherche récursive qui alterne entre des étapes d'"expectation" (testant tous les emplacements et valeurs possibles des tuiles, et pondérant leurs scores optimisés par la probabilité de chaque possibilité), et des étapes de "maximisation" (testant tous les mouvements possibles et sélectionnant celui qui a le meilleur score). La recherche arborescente se termine lorsqu'elle voit une position précédemment vue (à l'aide de la fonction table de transposition ), lorsqu'il atteint une limite de profondeur prédéfinie, ou lorsqu'il atteint un état du plateau hautement improbable (par exemple, il a été atteint en obtenant 6 tuiles "4" d'affilée depuis la position de départ). La profondeur de recherche typique est de 4 à 8 coups.
Heuristique
Plusieurs heuristiques sont utilisées pour diriger l'algorithme d'optimisation vers des positions favorables. Le choix précis de l'heuristique a un effet considérable sur les performances de l'algorithme. Les différentes heuristiques sont pondérées et combinées en un score positionnel, qui détermine la "bonne" position d'un échiquier donné. La recherche d'optimisation vise alors à maximiser le score moyen de toutes les positions de plateau possibles. Le score réel, tel qu'il apparaît dans le jeu, est le suivant no utilisé pour calculer le score du conseil, car il est trop fortement pondéré en faveur de la fusion des tuiles (lorsque la fusion retardée pourrait produire un grand avantage).
Au départ, j'ai utilisé deux heuristiques très simples, accordant des "bonus" pour les carrés ouverts et pour avoir de grandes valeurs sur le bord. Ces heuristiques ont donné d'assez bons résultats, atteignant fréquemment 16384 mais jamais 32768.
Petr Morávek (@xificurk) a pris mon IA et y a ajouté deux nouvelles heuristiques. La première heuristique consistait en une pénalité pour les rangs et les colonnes non monotones, qui augmentait à mesure que les rangs augmentaient, de sorte que les rangs non monotones de petits nombres n'affectent pas fortement le score, mais que les rangs non monotones de grands nombres le pénalisent considérablement. La deuxième heuristique comptait le nombre de fusions potentielles (valeurs égales adjacentes) en plus des espaces ouverts. Ces deux heuristiques ont servi à pousser l'algorithme vers les tableaux monotones (qui sont plus faciles à fusionner) et vers les positions de tableau avec beaucoup de fusions (l'encourageant à aligner les fusions lorsque cela est possible pour un meilleur effet).
En outre, Petr a également optimisé les poids heuristiques à l'aide d'une stratégie de "méta-optimisation" (en utilisant un algorithme appelé CMA-ES ), où les pondérations elles-mêmes ont été ajustées pour obtenir le score moyen le plus élevé possible.
L'effet de ces changements est extrêmement important. L'algorithme est passé de l'obtention de la tuile 16384 environ 13 % du temps à l'obtention de cette tuile plus de 90 % du temps, et l'algorithme a commencé à obtenir 32768 plus d'un tiers du temps (alors que l'ancienne heuristique ne produisait jamais une tuile 32768).
Je pense qu'il est encore possible d'améliorer l'heuristique. Cet algorithme n'est certainement pas encore "optimal", mais je pense qu'il s'en rapproche.
Le fait que l'IA réussisse à atteindre la tuile 32768 dans plus d'un tiers de ses parties est une étape importante ; je serais surpris d'apprendre qu'un joueur humain a réussi à atteindre 32768 sur le jeu officiel (c'est-à-dire sans utiliser d'outils comme les sauvegardes ou l'annulation). Je pense que la tuile 65536 est à portée de main !
Vous pouvez essayer l'IA par vous-même. Le code est disponible à l'adresse suivante https://github.com/nneonneo/2048-ai .
87 votes
Cela pourrait aider ! ov3y.github.io/2048-AI
5 votes
@nitish712 au fait, votre algorithme est gourmand puisque vous avez
choose the move with large number of merges
qui conduisent rapidement à des optima locaux22 votes
@500-InternalServerError : Si I Si l'on devait implémenter une IA avec un élagage de l'arbre de jeu alpha-bêta, elle supposerait que les nouveaux blocs sont placés de manière contradictoire. C'est la pire des hypothèses, mais elle pourrait être utile.
7 votes
Une distraction amusante lorsque vous n'avez pas le temps de viser un score élevé : Essayez d'obtenir le score le plus bas possible. En théorie, il s'agit d'alterner les 2 et les 4.
0 votes
@AnonymousPi il est en fait théoriquement impossible d'avoir un jeu sans une seule fusion, même si vous essayez de le faire, car le rapport de génération de deux à quatre est de 9:1.
7 votes
La discussion sur la légitimité de cette question peut être trouvée sur meta : meta.stackexchange.com/questions/227266/
1 votes
Si quelqu'un cherche une implémentation de l'apprentissage par renforcement (non supervisé) en utilisant Keras et Tensorflow, mon code est ici. github.com/codetiger/MachineLearning-2048
0 votes
jdlm.info/articles/2018/03/18/markov-processus-de-decision-2048.html ... si vous souhaitez comprendre le jeu optimal avec les MDP, ce blog l'explique succinctement.
0 votes
La question est de trouver une stratégie optimale. Toutes les réponses données jusqu'à présent portent sur des approximations de l'IA. La façon évidente, mais pourtant ignorée, d'obtenir une stratégie optimale est d'appliquer les mathématiques au problème. Si tous les modèles et toutes les composantes des modèles peuvent être exprimés de manière algébrique (groupe), il est possible d'établir des théorèmes concernant les chemins qui mènent du départ à la victoire et la manière dont leurs segments se combinent. Contrairement aux échecs ou au Go, qui sont trop difficiles à analyser complètement, 2048 possède une simplicité mathématique qui pourrait rendre cette analyse possible. Tetris aussi ? Et des parties du Rubik's Cube ?