La programmation des moteurs d'échecs est un territoire très compliqué, donc dès le départ, je vous pointerai vers le wiki de programmation des échecs , qui contient beaucoup d'informations sur ce sujet.
Contexte
Les calculs d'échecs (et bien d'autres choses similaires) sont généralement modélisés et considérés comme des «arbres de jeu» ou des « arbres de décision ». Globalement, cet arbre est un graphique dirigé, avec un nœud en haut (la position actuelle), menant à un nœud pour chaque mouvement possible, chacun conduisant à plus de nœuds pour chaque prochain mouvement possible , et ainsi de suite.
Dans leur forme de force brute la plus simpliste, les moteurs d'échecs génèrent toutes les positions sur cet arbre jusqu'à une certaine limite de profondeur ("ply"), évaluant chaque position résultante sur la base de certains critères complexes 1 . Ensuite, il joue le coup qui semble conduire au meilleur résultat. De nos jours, beaucoup de techniques vraiment compliquées ont été développées pour limiter le nombre de positions que le moteur doit regarder, mais je vais les ignorer pour cette réponse, car elles ne changent pas le vrai problème à main.
Math Tangent
La raison fondamentale pour laquelle les moteurs prennent généralement environ la même quantité de temps pour considérer chaque mouvement est que la taille de l'arbre de décision augmente de façon exponentielle avec depth ( k
).
Considérez la position de départ. Le sommet de l'arborescence ( k=0
) est un nœud. Il y a vingt premiers mouvements possibles pour les Blancs, il y a donc vingt nœuds en profondeur k=1
. Ensuite, les Noirs ont également vingt coups disponibles pour chacune des options des Blancs: donc k=2
, il y a 20 * 20 = 400
des positions possibles! Et cela ne fait qu'empirer à mesure que les joueurs développent leurs pièces!
Par exemple, supposons qu'il y ait toujours vingt coups possibles pour chaque joueur à un moment donné 2 . Vous demandez à l'ordinateur d'anticiper cinq coups pour chaque joueur (dix plis). Regardons la taille de l'arbre de force brute à chaque niveau. Pour le plaisir, nous allons également regarder le nombre total de positions dans l'arbre (du haut au niveau donné).
Ply | Positions | Total Tree Size
----------------------------------------
0 | 1 | 1
1 | 20 | 21
2 | 400 | 421
3 | 8000 | 8421
4 | 160000 | 168421
5 | 3200000 | 3368421
6 | 64000000 | 67368421
7 | 1280000000 | 1347368421
8 | 25600000000 | 26947368421
9 | 512000000000 | 538947368421
10 | 10240000000000 | 10778947368421
Le résultat de chaque niveau étant exponentiellement plus grand que le niveau précédent est que la taille de l'arbre entier est dominée par le niveau inférieur . Prenons l'exemple ci-dessus: le dernier niveau contient à lui seul dix mille milliards de nœuds. Le reste de l'arbre ne contient que cinq cent milliards. Le dixième pli contient environ 95% des nœuds de l'arbre entier (c'est en fait vrai à chaque niveau). En pratique, cela signifie que tout le temps de recherche est consacré à l'évaluation du "dernier" mouvement.
Répondre
Alors, comment cela se rapporte-t-il à votre question? Eh bien, disons que l'ordinateur est réglé sur dix plis, comme ci-dessus, et en outre, il "se souvient" des résultats de ses évaluations. Il calcule un coup, le joue, puis vous faites un coup. Maintenant, deux mouvements ont été effectués, donc il taille toutes les positions de la mémoire liées aux mouvements qui n'ont pas eu lieu, et il reste un arbre qui descend les huit mouvements restants qu'il a déjà calculés: 26 947 368 421 positions!
D'accord! Il nous suffit donc de calculer les deux derniers plis! En utilisant notre estimation de 20 mouvements à chaque profondeur, le nombre total de mouvements que nous devons calculer ici est toujours supérieur à 10 000 milliards. Les positions que nous avons déjà calculées ne représentent que 2,5% des possibilités! Donc, même en mettant en cache les résultats du dernier mouvement, le mieux que nous puissions espérer est une augmentation de 2,5% de la vitesse! Au fond, c'est pourquoi même si votre programme met en cache les résultats précédents, vous ne voyez généralement pas d'accélération significative entre les mouvements (sauf dans les cas où l'ordinateur trouve un partenaire forcé ou quelque chose, bien sûr!).
Clause de non-responsabilité relative à la simplification
Il y a beaucoup de complexité impliquée dans cette question, c'est pourquoi j'ai lié au wiki de programmation tout en haut et j'ai seulement essayé d'expliquer la réponse en termes mathématiques généraux. En réalité, les programmes mettent généralement en cache des parties de l'arbre d'un mouvement à l'autre, et il y a d'autres raisons pour lesquelles cela est insuffisant en soi - quelques raisons simples (par exemple, une certaine ligne peut sembler bonne à huit mouvements, mais se termine par un retour) -mate mate on move nine!) et de nombreux très compliqués (généralement liés à diverses méthodes d'élagage intelligentes). L'ordinateur doit donc continuer à regarder plus loin pour éviter de faire de mauvaises hypothèses en fonction de la profondeur de coupure du mouvement précédent.
1 Je ne vais pas entrer ici dans les fonctions heuristiques, car c'est sa propre zone incroyablement complexe, mais il y a souvent des gains qui peuvent également être obtenus via des schémas de mise en cache de position.
2 Un facteur de ramification moyen de 20 est probablement beaucoup trop faible .
Un moteur d'échecs typique stockera certaines des positions et leurs scores alpha-bêta entre crochets dans un tableau de transposition qui peut être consulté lors des recherches ultérieures. Ce tableau n'est pas consulté directement pour choisir le prochain mouvement, mais il rend la recherche de ce mouvement plus efficace de deux manières.
Une position sera probablement rencontrée plusieurs fois dans un arbre de recherche, atteinte par une transposition ou permutation d'une séquence de mouvements. Étant donné que le tableau peut être consulté, une telle position peut ne devoir être évaluée que quelques fois (pour différentes profondeurs de recherche fixes) au lieu de dizaines de fois lorsque la position est visitée et revisitée.
Une technique standard pour les recherches alpha-bêta est d'utiliser l' approfondissement itératif , en sondant à plusieurs reprises l'arbre à une plus grande profondeur de recherche jusqu'à ce que la profondeur terminale soit atteinte. Les scores d'évaluation calculés dans les itérations précédentes sont utilisés pour ordonner les mouvements recherchés dans les itérations ultérieures. L'alpha-bêta est connue pour donner de meilleurs résultats (c.-à-d. Élaguer davantage l'arbre de recherche) si les bons coups sont recherchés avant les mauvais coups.
la source
Exemple illustrant la mémoire du moteur:
EDIT: La réponse originale (gardée ci-dessous) est fausse, cependant, elle fournit un exemple utile de la mémoire du moteur, qui a été citée en haut.
Pour autant que je sache, ils ne le font pas, c'est-à-dire qu'ils lancent la recherche dans l'arbre presque à partir de zéro à chaque mouvement.
Cependant, ils doivent avoir une sorte de fonction qui actualise les valeurs pour chaque mouvement, et cette fonction a sûrement de la mémoire à court terme. Quelques exemples sont des positions où de profondes nouveautés théoriques sont découvertes, en particulier le jeu Caruana vs Topalov joué cette année. Lorsque vous laissez le moteur analyser la position après le coup 12 pendant une durée plus ou moins courte (disons 10 à 15 minutes), vous pouvez vérifier les mouvements suggérés et voir que le TN (
13.Re2!
) n'apparaît pas parmi eux. Introduisez vous-même le mouvement, reculez et laissez le moteur analyser à nouveau la même position plus ou moins en même temps. Étonnamment, après réflexion, le moteur considère maintenant le TN parmi les meilleurs mouvements et l'approuve.Je ne suis pas un expert des logiciels d'échecs, mais cela arrive. Cela peut être expliqué au moins partiellement si (comme dit) la fonction qui évalue les mouvements pour la position a de la mémoire.
la source
Henry Keiter vous a déjà donné une réponse générale, je vais vous donner une réponse plus technique. Il s'agit de table de transposition, de profondeur de recherche et de coupure. La discussion ici est BEAUCOUP plus technique que les autres réponses, mais elle sera bénéfique à quiconque veut apprendre la programmation des échecs.
C'est un malentendu commun que si une position a été évaluée auparavant, le score d'évaluation pourrait être réutilisé tant qu'il y a suffisamment de mémoire pour stocker les mouvements. La programmation des échecs est plus compliquée que cela. Même avec une mémoire infinie, il vous faudrait encore rechercher les positions. Pour chaque coup, un score d'évaluation est attaché avec sa profondeur et sa limite. Par exemple, si le moteur stocke un mouvement par échec, l'entrée de table aurait une limite inférieure. Cela signifie que si vous cherchez un poste, vous devrez toujours vérifier les limites si vous pouvez utiliser le score d'évaluation précédent.
En dehors de cela, chaque évaluation a une profondeur qui lui est attachée. Dans un cadre d'approfondissement itératif, à mesure que vous augmentez la profondeur de chaque itération, vous devrez toujours rechercher les positions que vous avez déjà recherchées dans l'itération précédente.
La réponse courte à votre question est qu'un moteur stocke toutes les positions analysées précédentes (tant qu'il y a suffisamment de mémoire), mais ces résultats stockés ne peuvent pas être réutilisés aussi facilement que vous auriez pu le penser . Dans une phase d'ouverture où il y a moins de répétitions, ces résultats stockés sont les plus utiles pour l'ordre des mouvements et une douzaine d'heuristiques de réduction des mouvements. Par exemple, on supposerait que le meilleur mouvement depuis la dernière profondeur est le meilleur mouvement dans la profondeur actuelle, nous trions donc les listes de mouvements et recherchons le meilleur mouvement avant tout autre mouvement. Avec un peu de chance, nous obtiendrions un seuil d'échec élevé.
Nous n'avons pas de mémoire infinie pour stocker les positions. Nous aurions besoin de définir un algorithme de hachage. L'algorithme de hachage de Zobrist nous donne une distribution pseudo-aléatoire, mais tôt ou tard nous devrons toujours remplacer certaines entrées existantes.
la source
Chaque moteur a son propre schéma de gestion du temps. Certains moteurs et interfaces graphiques vous permettent de définir le rythme auquel le moteur va jouer. Les moteurs calculent / évaluent / minimalisent toujours autant qu'ils le peuvent compte tenu des contraintes imposées par les sous-programmes de gestion du temps ou les paramètres utilisateur. Si un moteur réfléchit depuis longtemps, c'est probablement parce que le contrôle du temps pour le jeu est lent, ou que l'utilisateur l'a réglé pour jouer lentement.
Les positions et les évaluations que le moteur a calculées sont stockées dans une table de hachage. L'utilisateur peut définir la taille du hachage disponible dans les paramètres de la plupart des moteurs UCI. Le moteur lui-même utilise une certaine quantité de RAM et si vous définissez une taille de table de hachage trop élevée, l'ordinateur commencera à stocker du hachage sur votre disque dur sous forme de RAM virtuelle. La mémoire du disque dur est accessible plus lentement que la RAM, et vous pourrez généralement entendre le disque dur se désagréger. De nombreux utilisateurs définissent la taille de la table de hachage afin qu'elle tienne dans la RAM disponible.
Une grande partie de n'importe quelle table de hachage devient inutile après que le moteur et son adversaire ont effectué leurs mouvements car les autres positions considérées ne sont plus pertinentes. Le moteur réutilisera les évaluations stockées dans le hachage, mais certaines évaluations s'avèrent incorrectes en raison des effets d'horizon une fois que le moteur descend plus profondément sur la même ligne, il doit donc souvent réorganiser ses mouvements candidats.
Étant donné que la quantité de hachage est limitée, un moteur doit également prendre des décisions quant aux informations à supprimer de son hachage lors de l'ajout de nouvelles informations. Le moteur ne sait pas à l'avance quels mouvements seront joués, il peut donc supprimer par inadvertance des informations qui auraient été utiles lors de l'ajout de nouvelles données.
Les moteurs en général n'examinent pas tous les mouvements légaux à une certaine profondeur. Ils éliminent certaines branches de l'arbre de la considération basée sur l'élagage avant et arrière. De plus, si une position de nœud terminal a des captures ou des vérifications à effectuer, le moteur continuera sur cette ligne jusqu'à ce qu'il atteigne une position calme (au repos). L'arbre réel est probablement assez profond à certains endroits, tandis que d'autres lignes peuvent avoir été tronquées après un petit nombre de mouvements.
la source