rZbm skZ opZ a Zp l ZpmpZ Z opZ M Z O M Z Z OBZ Z …burgot.ensae.net/projects/chessreport.pdf ·...

of 28/28
2 800 ×
  • date post

    13-Sep-2018
  • Category

    Documents

  • view

    217
  • download

    0

Embed Size (px)

Transcript of rZbm skZ opZ a Zp l ZpmpZ Z opZ M Z O M Z Z OBZ Z …burgot.ensae.net/projects/chessreport.pdf ·...

  • BibiChess

    Lucas Braesch & Romain Burgot

    7 juin 2006

    rZbm skZopZ a Zpl ZpmpZZ opZ MZ O M ZZ OBZ ZPOQZ OPOS A ZRJ

    Fig. 1 TARRASCH ECKART (1889)Blanc joue et gagne.

    Rsum

    On se propose ici d'crire un programme en C++, capable de jouer aux checs. Aujourd'hui,

    il existe de nombreux logiciels gratuits, dont les meilleurs culminent prs de 2 800 elo. Bienentendu, nos ambitions sont trs infrieures, mais le programme devra au moins jouer des

    coups tactiquement correct et ne pas boguer. Pour prendre un exemple caractristique,

    il trouvera 14. Bg6 ! dans la position de la Fig. 1, mais n'arrivera probablement pas construire une telle position tout seul.

    1

  • TABLE DES MATIRES 2

    Table des matires

    Introduction 2

    1 Principe de l'IA 41.1 L'algorithme minmax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.2 Extensions tactiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

    2 Amliorations de l'algorithme 82.1 L'algorithme PVS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82.2 Hash Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112.3 Heuristiques d'lagage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

    3 Implmentation 143.1 Les BitBoards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143.2 Evaluation positionnelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

    4 Tests et rsultats 234.1 Validation du gnrateur de coups . . . . . . . . . . . . . . . . . . . . . . . . . . 234.2 Performances . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

    Conclusion 24

    A Pr requis 25A.1 Rgles du jeu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25A.2 Notation des coups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25A.3 Notation FEN des positions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

    B Interface UCI 26B.1 Manuel de l'utilisateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26B.2 Le protocole UCI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

    KQRBNp

    Introduction

    Avant de commencer la lecture de ce rapport, le lecteur non-spcialiste des checs pourra sereporter aux annexes :

    les rgles spciques du jeu d'chec, brivement rappeles en annexe : A.1. la notation standard des coups, qui sera largement utilise par la suite : voir A.2.

    Par ailleurs, nous tenons signaler que le programme ne fonctionne pas tout seul, mais aumoyen d'une interface externe. An de pouvoir le tester, nous renvoyons le lecteur au manuel del'utilisateur, en annexe B.1.

    Cahier des charges

    Notre but est d'crire un programme capable de jouer une partie d'chec complte :

    1. Celui-ci devra donc tre capable de rsoudre des problmes tactiques (comme la Fig. 1),mais aussi de jouer de faon stratgique : dvelopper ses pices, contrler le centre etavancer selon un plan.

    2. De plus, il faudra que l'utilisateur puisse bncier d'une interface conviviale pour aronterle programme, ou le voir aronter d'autres programmes.

  • TABLE DES MATIRES 3

    3. Enn, le programme pourra consulter une bibliothque d'ouvertures pour les premierscoups.

    Choix techniques

    Plusieurs choix techniques s'imposent alors. D'abord le choix du langage de programmation :nous avons choisi C/C++. Cela signie donc que le code est crit en C++, avec certaines partiesen C. En voici brivement les raisons :

    1. Nous avons besoin d'un langage orient objet, parce que c'est pratique et agrable.

    2. Cependant, nous avons aussi besoin d'un langage de bas niveau, pour des raisons ecacit.En l'occurrence, BibiChess utilise la fameuse mthode des bitboards pour la gnrationdes coups. Nous verrons cela plus tard, mais disons juste que nous avons absolument besoind'oprateur bit bit sur des entiers 64 bits.

    En ce qui concerne l'interface, nous avons choisi de relguer cette partie un programmeextrieur, avec lequel nous communiquons via un protocole standard, nomm Universal ChessInterface (UCI). De nombreuses raisons justient ce choix :

    1. Coder nous mme une interface est une tche longue et peu intressante. Nous prfronsnous concentrer sur le moteur en tant que tel. De plus, les interfaces existantes voluenttoutes seules et nous bncions ainsi gratuitement de ces volutions.

    2. En fait, crire nous mme l'interface est non seulement pnible, mais mme pas souhai-table. En eet, une interface MFC propre notre programme sourirait ncessairementdes limitations suivantes :

    (a) L'impossibilit de jouer des tournois automatiques avec d'autres programmes, essentielpour amliorer le BibiChess.

    (b) Il aurait fallu coder nous mme la gestion du livre d'ouverture. Pour commencer ilaurait fallu en crer un, donc crire un compilateur de parties PGN1. Heureusement,les interfaces UCI font cela trs bien notre place.

    (c) La portabilit des MFC est trs limite2, tandis qu'un code ANSI C++ comme le notredevrait fonctionner sur n'importe quel compilateur et n'importe quelle plate-forme3.

    Ce rapport s'articule en 3 parties. Dans un premier temps, nous prsentons les algorithmesutiliss (parties 1 et 2). Ensuite, nous verrons les lments principaux de l'implmentation : lagnration des coups et l'valuation positionnelle. Enn, nous prsenterons brivement le travailde dboguage eectu tout au long du projet.

    1Portable Game Notation : la notation standard des parties.2seul Visual C++ compile un programme MFC et seul Windows peut excuter le code compil.3. . . un dtail prs toutefois, la fonction rst_bit code en assembleur Intel pour des raisons d'ecacit.

  • 1 PRINCIPE DE L'IA 4

    1 Principe de l'IA

    1.1 L'algorithme minmax

    1.1.1 Approche thorique

    Une partie d'chec ne prsente que 3 issues : blanc gagne, noir gagne ou partie nulle. L'arbredu jeu tant ni, on s'aperoit par induction rtrograde qu'il existe des quilibres de Nashparfaits. Cela signie donc qu'une (exactement) des trois propositions suivantes est vraie :

    1. blanc possde une stratgie gagnante,

    2. noir possde une stratgie gagnante,

    3. blanc et noir possdent tous les deux une stratgie de partie nulle. Autrement dit, blancpeut au moins forcer la nulle contre toute dfense de noir et inversement. Ainsi deux joueursinniment intelligents ne feraient que des parties nulles.

    Mme si ce n'est pas prouv, il est probable que l'quilibre du jeu d'chec soit une partie nulle.Cela signie qu' chaque coup, il existe une correspondance de meilleure rponse, assurant la nullecontre toute dfense. Ainsi, ds qu'un des deux joueurs sort de cette correspondance, l'autre peutle sanctionner par une stratgie gagnante.

    1.1.2 valuation d'une position

    Hlas, le seul moyen de connatre la correspondance de meilleure rponse d'un noeud donnde l'arbre est d'eectuer une recherche rcursive allant jusqu'aux feuilles de l'arbre, sur lesquelleson peut attribuer des scores +,, 0 (gagner, perdre ou annuler) : c'est la stratgie minmaxau sens de la thorie des jeux. Malheureusement, la taille de l'arbre est gigantesque et ceci esttout simplement impossible. On cherchera donc eectuer un minmax local, en appliquant leprincipe d'induction rtrograde sur un arbre extrait de taille limite. Pour cela, il faut attribuer chaque noeud (pas seulement aux feuilles) des scores. Assez naturellement le score d'un joueursera la somme

    d'un score matriel : nombre de points, en comptant classiquement

    p = 1, N =B = 3, R = 5, Q = 9

    et d'un score positionnel : activit des pices, scurit du roi, pions passs, isols, doubls,arrirs, bon fou, mauvais fou, paire de fou etc. . .

    Autrement dit, on veut que le programme ne rchisse pas uniquement en termes tactiquesmais aussi en termes positionnels, c'est--dire qu'il ait une culture du jeu d'chec et une intuition,de faon jouer comme s'il avait un plan un peu construit. Enn, le score de blanc est la direncede son score et de celui des noirs et inversement. Ainsi, les scores sont symtriques (de sommenulle tout le temps). Un bonus positionnel ou matriel pour blanc sera donc un malus pour noir et inversement. Par consquent, l'ordinateur cherchera de manire gale consolider sa position,ou a dtruire celle de l'adversaire (c'est pourquoi il jouera un peu selon un plan).

    1.1.3 L'algorithme minmax

    Le programme doit donc chercher le meilleur coup en sachant que son adversaire fait de mmeet ainsi de suite... Le raisonnement doit s'arrter une certaine profondeur. Autrement dit :

    1. le meilleur coup de A profondeur d est obtenu en jouant tous les coups possibles et en rete-nant celui qui minimise le score de B, partant du principe que B applique ce raisonnement profondeur d 1.

  • 1 PRINCIPE DE L'IA 5

    2. le meilleur coup de A profondeur 1 est obtenu en jouant tous les coups possibles et enretenant celui qui maximise le score de A ou minimise le score de B sans tenir comptedes rponses de B.

    Dans un pseudo-code, volontairement imprcis, voila comment se prsente l'algorithme min-max :

    search(depth)

    {

    loop through all moves {

    play move

    if (depth > 1) move_score = -search(depth-1) // rcursion sur les noeuds

    else score = static_position_score // valuation des feuilles

    best = max(best, score)

    undo move

    }

    return best

    }

    1.1.4 L'eet d'horizon

    Nous allons voir ici, travers un exemple caractristique, que l'algorithme minmax de basepeut vritablement jouer des coups stupides. En fait, nous verrons que ce n'est pas la stratgieminmax en tant que telle qui est en cause, mais l'arbre sur lequel nous l'appliquons : on ne peutpas se contenter d'un arbre profondeur xe.

    Z Z Z ZZ m ZklZ o obaZpoPZ ZZPZ ZQZZPA ZNOPZ ZRZKZZ Z Z Z

    Profondeur Variante Gain matriel

    1 Qg6+ B = +32 Qd7+ 0

    2 cb5 03 Qd7+ Q = +94 Qc8 N = +3

    Fig. 2 Inconsistance de l'algorithme minmax.

    tude d'un exemple. Sur la Fig. 2, nous voyons clairement l'inconsistance du minmax.En eet, les scores profondeur n et n + 1 n'ont gnralement rien voir entre eux :

    1. A profondeur 1, le meilleur coup au sens minmax est 1. Qg6+ ?. On value alorsdirectement la position, alors que blanc a une dame en prise !

    2. A profondeur 2, le minmax comprends enn que 1. Qg6+ ? est rfut par 1. . . . Qg6.En fait, toute capture des blancs est directement re-capture. Ainsi le minmax prfrera1. Qd7+, qui force 1. . . . Kf8 ou 1. . . . Kg8 : ici, le score minmax est donc nul.

    3. A profondeur 3, le minmax prfrera : 1. Qd7+ Kf8; 2. Qg7+. Il pensera donc gagnerune dame sec, sans jamais envisager les re-captures 2. . . . Kg7 ou 2. . . . Bg7.

    4. Ce n'est donc qu'a profondeur 4 qu'il trouve le bon coup 3. Qc8 !

    Conclusion. Plutt que de s'appesantir d'avantage sur ce genre d'exemple (qui ne manquepas), cherchons plutt en tirer des conclusions, an de dnir correctement l'arbre explorer.Il ne s'agit donc pas d'un arbre profondeur quilibre, cause d'un eet d'horizon manifeste :

  • 1 PRINCIPE DE L'IA 6

    on ne peut pas valuer n'importe quelle position. Ainsi, valuer une position dans laquelle il restedes squences de captures, ou une position en chec, donne des rsultats pour le moins douteux.

    1.2 Extensions tactiques

    1.2.1 Quiescent search

    Pour rsoudre le problme d'instabilit de la recherche minmax, nous venons de voir pourquoiil est impratif de n'valuer que des positions calmes, c'est--dire sans captures ni chec. Eneet, la moindre des choses, avant mme de penser valuer quelque score positionnel que cesoit, est de rsoudre les suites de captures et d'checs. La solution classique ce problme (voir[5]), appele quiescent search4 eectue, en partant des feuilles de l'arbre :

    1. une recherche profondeur innie sur les captures,

    2. en tendant les checs qui en rsultent.

    Dans un pseudo code un peu simpli, voici ce que cela signie :

    quiesce()

    {

    score = eval()

    if we're in check {

    move_list = all legal moves // check escapes

    if none return -MATE // no escape -> we're mate

    } else move_list = captures only

    loop trough the move_list {

    play(move)

    score = max(score, -quiesce())

    undo(move)

    }

    return score

    }

    Il faut bien noter la premire ligne score = eval(), qui a pour eet de laisser le choix auprogramme d'initier la squence de captures, ou bien de se contenter du score actuel. Eective-ment, le meilleur coup n'est gnralement pas une capture. On constatera aussi que le quiescentsearch peut trouver des mat. Par exemple, aprs 1. f4 e5; 2. fe5 d6; 3. fd6 Bd6; 4. Nc3 ?[4. Nf3]; l'algorithme trouve un mat a profondeur 1, grce aux extensions du quiescent search(Fig. 3).

    En eet, aprs 4. . . . Qh4+ ! le quiescent search trouve directement la suite de captureset d'checs 5. g3 Qg3+; 6. hg3 Bg3m. De la mme faon, 5. . . . Bg3+; 6. hg3+Qg3m donne le mme rsultat. Enn, n'oublions pas que le minmax standard ne trouve le matqu' profondeur 5, ce qui ncessite environ 405 100 millions de coups calculer. De plus, lemeilleur coup profondeur 1 au sens minmax est 4. . . . Bh2 ?.

    1.2.2 Extensions de recherche

    Toujours dans la mme ide (rsoudre en priorit les variantes tactiques), il faut rajouterdes extensions au minmax normal : chec, re-capture, coup forc, pousse de pion en septimerange. Ainsi, l'arbre de recherche utilis (minmax + quiescent search) devient assez dsquilibr.Concrtement, l'algorithme minmax du 1.1.3 se rcrit ainsi, pour tenir compte des extensionset du quiescent search :

    4Quiescent est synonyme de quiet en anglais : silencieux. Les boules Quies sont un bon moyen mnmotech-nique.

  • 1 PRINCIPE DE L'IA 7

    rmblkZnsopo ZpopZ a Z ZZ Z Z ZZ Z Z ZZ M Z ZPOPOPZPOS AQJBMR

    rmbZkZnsopo ZpopZ a Z ZZ Z Z ZZ Z Z lZ M Z ZPOPOPZPOS AQJBMR

    Fig. 3 Rsolution de mat par le quiescent search.

    search(depth)

    {

    if (no legal move) return in_check ? -MATE : 0 // mate or stalemate

    if (in check, recapture, 1 legal move, pawn-push to 7th rank) depth++

    loop through all moves {

    play move

    score = depth > 1 ? -search(depth-1) : -quiesce()

    undo move

    best = max(best, score)

    }

    return best

    }

    1.2.3 Retour sur l'exemple 1.1.4

    Nous reprenons ici l'exemple de la Fig. 2, an de mieux comprendre dans quelle mesureles extensions tactiques prcdentes amliorent la qualit de l'algorithme. En utilisant les exten-sions de recherche (re-capture, chec, pousse de pion en septime range) et le quiescent search(captures et position en chec), voici les rsultats obtenus :

    1. A profondeur 1, nous obtenons dj : 1. Qd7+ Kg8; 2. Qd6 bc4; 3. bc4 et les blancsgagnent un pion.

    2. A profondeur 2 : 1. Qc8 Qf8; 2. Qc7+ Kg8 et les blancs gagnent un cavalier.On obtient ainsi le bon coup profondeur 2, ainsi qu'a toute profondeur suprieure. L'amlio-ration apporte par les extensions tactiques est donc norme, d'autant plus que l'algorithme estdsormais stable. Nous avons largement rduit l'eet d'horizon qui donnait des rsultats dlirants,comme le score +9 obtenu par le minmax profondeur 3 1. Qd7+ Kf8; 2. Qg7+.

  • 2 AMLIORATIONS DE L'ALGORITHME 8

    2 Amliorations de l'algorithme

    Jusqu' prsent, nous avons cherch bien dnir l'arbre sur lequel il convient d'appliquerla stratgie minmax. Rappelons que la construction de cet arbre se rsume un principe de bonsens : rsoudre les squences tactiques en priorit, avant toute valuation. Le problme qui sepose maintenant est la taille norme de l'arbre parcourir. Bien entendu, la complexit del'algorithme est en O(bn), o n est la profondeur et b est le facteur de branchement de l'arbre (i.e.nombre moyen de branches par noeud). Nous allons voir qu'il existe des techniques de pruning5,permettant de rduire sensiblement le nombre b. Ces techniques de pruning peuvent tre classesen deux catgories :

    1. Les mthodes de pruning thoriquement fondes, c'est--dire dont on peut dmontrerqu'elles obtiennent le mme rsultat que le minmax non optimis en rduisant l'arbre parcourir. Ces mthodes se rsument essentiellement l'algorithme PVS (voir 2.1) et lesHash Tables (voir 2.2).

    2. Les mthodes heuristiques, thoriquement non fondes, mais empiriquement valables, quenous verrons en 2.3.

    2.1 L'algorithme PVS

    2.1.1 Un exemple

    L'Alpha-beta pruning est une astuce qui rduit normment la taille de l'arbre. Pour l'ins-tant, l'algorithme minmax recherche chaque rponse possible, pour tous les noeuds. Etant donnle facteur de branchement moyen (de l'ordre de 40), cette mthode est donc trop laborieuse.L'Alpha-beta pruning est base sur l'limination des menaces non-crdibles. Imaginons que leprogramme soit occup chercher tous les coups la racine de l'arbre. Pour l'instant, il a passles 6 premiers coups, et le meilleur score est 15 points6. Il cherche alors le 7eme et considreles rponses adverses. Il va donc boucler sur ces rponses adverses et trouver, disons, les scoressuivant :

    20,22,15,16,11,18,20,30,70,75

    Maintenant le meilleur de ces scores est 11, ce qui donne (11) = 11 au niveau de la racine.Ce score est moins bon que les 15 points trouvs prcdemment. Pourtant, le programme a perduson temps chercher les rponses adverses numro 6 10. En fait, ds qu'une rponse adversemarque 11 points, nous savons que ce coup ne pouvait pas battre le score 15 prcdent. Quelsque soient les scores adverses suivant (ici 18,20,30,70,75) nous savons que ce noeudn'est qu'une menace non crdible (le premier joueur n'a pas intrt y aller).

    2.1.2 Alpha-beta pruning

    Concrtement, chaque noeud est associ un intervalle [, ] qui correspond la fourchettede score admissible (tout score extrieur [, ] est rfut en amont de l'arbre). A partir de l,le code devient tout simple7 :

    search(depth, alpha, beta)

    {

    if (no legal move) return in_check ? -MATE : 0 // mate or stalemate

    if (in check, recapture, 1 legal move, pawn-push to 7th rank) depth++

    loop through all moves {

    play move

    score = depth > 1 ? -search(depth-1,-beta,-alpha) : -quiesce(-beta,-alpha)

    5En anglais, to prune a tree = laguer un arbre, donc pruning = lagage.6En pratique, un pion vaut 100 points, ce qui permet de n'utiliser que des entiers pour coder le score.7On ne manquera pas de constater que la technique s'applique de la mme faon au quiescent search, ce qui

    explique l'utilisation d'une fourchette [,] dans la fonction quiesce.

  • 2 AMLIORATIONS DE L'ALGORITHME 9

    undo move

    alpha = max(alpha, score)

    if (alpha >= beta) return alpha

    }

    return alpha

    }

    Concrtement, l'amlioration est lie : if (alpha >= beta) return alpha. On appelle celaun -cuto. S'il y a typiquement 40 coups lgaux chaque noeud et que le -cuto apparat, enmoyenne, au beme, alors la complexit passe de 40n bn, ce qui n'est pas du tout ngligeable.

    2.1.3 Tri des coups et SEE

    Pour minimiser ce nombre b, il faut donc que les meilleurs coups se situent au dbut de laliste. Ainsi les -cuto apparaissent plus tt et les coups sont cherchs avec des fentres [, ]plus troites. La qualit du tri est un point crucial de l'algorithme, comme le souligne [5] : Theway to speed up a chess program very rarely lies with extremely fast move generation, nor does it

    lie with rapid check testing. The best way to achieve immediate and noticeable speed increases is

    to improve the move ordering. Notre tri est largement inspir de [6] :

    1. bonnes captures : il s'agit de captures initiant une squence de recaptures gagnante.

    2. checs, dplacements vers le centre, puis autres dplacements.

    3. mauvaises captures : captures initiant une squence de recaptures perdante.

    SEE. Pour dpartager les bonnes des mauvaises captures, nous utilisons une technique clas-sique appelle SEE8. Le SEE value simplement toutes les suites de recaptures possibles, and'estimer la valeur immdiate d'une capture : il s'agit d'une approximation rapide du quiescentsearch. La question que cherche rsoudre le SEE est donc la suivante : la squence de recapturesqu'initie une capture est-elle perdante ou gagnante pour le camp qui fait la capture initiale ?An de rpondre cette question, les coups qui seront envisags par le SEE ne seront que desrecaptures sur la case initiale de l'attaque que nous appellerons cible. On construit les listesde pieces qui attaquent et dfendent la case cible de l'chiquier, puis les joueurs vont jouerchacun leur tour :

    1. Si le joueur actif possde encore une pice pouvant capturer la case cible : il ralise cettecapture avec la pice de plus faible valeur. On doit ensuite ajouter la liste des attaquants,dfenseurs, une pice ventuelle qui peut dsormais accder la case cible.

    2. Si le joueur actif est incapable de re-capturer la case cible, alors l'algorithme s'arrte, etl'on dpile la squence de capture en sens inverse, an de savoir chaque tape s'il vautmieux pour le joueur actif faire la re-capture ou non.

    Il y a tout de mme une autre issue la boucle sur les joueurs : si l'un des joueurs fait unecapture avec le roi et que son adversaire possde encore une pice pouvant le re-capturer, il estvident que la capture faite avec le roi tait illgale. Voyons maintenant deux exemples, an decomprendre comment fonctionne le SEE et quelles sont ses faiblesses.

    Si l'on examine la promotion en dame du pion d (Fig. 4 gauche), la squence de capturessera la suivante : 1. d8=Q+ Nd8; 2. ed8+ Nd8; 3. Bd8+. En eet, reprendre la tourA8 ne sert rien puisqu'elle sera ensuite capture par la dame ou la tour, sans possibilit dere-capture par le roi. Le score renvoy par le SEE sera donc la valeur de deux cavaliers, moinscelle de deux pions. Considrons maintenant l'exemple de la promotion en E8. Il n'y aura aucunesquence de capture (car reprendre la tour ferait changer un pion contre une tour), et le scorerenvoy sera la valeur d'une dame moins celle d'un pion.

    8Static Exchange Evaluation : valuation Statique des changes.

  • 2 AMLIORATIONS DE L'ALGORITHME 10

    rZ Z Z ZZnjPOnZZ Z A ZZ Z Z ZZ Z Z LZ Z Z ZZ Z Z ZZ ZRJ Z

    Z Z ZkZZ Z ZrsZ Z Z ZZ Z Z ZZ Z Z ZZ Z ZPZZ Z ZPZZ Z Z J

    Fig. 4 Exemples de SEE.

    Il s'agit l de cas o l'analyse du SEE est relativement correcte. Voyons maintenant, sur laFig. 4 droite, un exemple qui met le SEE en dfaut. Le score renvoy par la SEE pour laprise du pion F par la tour sera dsavantageux pour noir, car le SEE ne prte pas attention auxclouages, donc il va considrer que le blanc pourrait prendre la tour au pion G. Le score serait lemme si le roi blanc tait remplac par une dame blanche. Bien que ce deuxime coup soit lgal,il entranerait la perte de la dame, chose qui n'est pas vu par le SEE dans la mesure o cela seproduit ailleurs que sur la case de re-capture F3.

    Le SEE n'est aucunement une valuation exacte des changes comme nous venons de le voir.Mais c'est cette simplication du problme qui fait sa force. Considrant des rgles plus simplesque celles des checs, il peut rsoudre rapidement les squences de capture sur une case unique,sans que nous ne gnrions les coups lgaux.

    2.1.4 Le PVS

    Le Principal Variation Search (PVS) est un ranement de l'alpha-beta pruning. Le postulatde dpart est que l'on dispose d'une bonne fonction de tri des coups. En particulier, le premierest frquemment le meilleur. Dans ce cas, il n'est souvent pas ncessaire de chercher les coupssuivant, de faon aussi exhaustive que le premier. Plus prcisment, on se che de savoir leurscore exact, tant que celui-ci est . Ainsi, nous cherchons le premier coup correctement, et lessuivant sont d'abord cherchs avec une fentre [[, + 1]] :

    if (first_move) // do the first one thoroughly

    score = -search(depth-1, -beta, -alpha)

    else { // try zero window first

    score = -search(depth-1, -(alpha+1), -alpha)

    if (score > alpha && beta > (alpha+1)) // fail high: current move improves alpha

    score = -search(depth-1, -beta, -alpha) // PVS re-search

    }

    Si notre hypothse s'avre exacte et que le meilleur coup est le premier de la liste, alors larecherche des coups suivant sera beaucoup plus rapide. En revanche, si un des coups suivantamliore , un -cuto sur la fourchette [[, +1]] en principe rapide indique que ce coup estmeilleur que . Comme son score est tronqu suprieurement (par + 1) il faut le re-cherchercorrectement, c'est--dire dans toute la fourchette [[, ]].

    En principe, le gain de temps li aux recherches fructueuses sur des fentres troites [[, +1]] contrebalance la perte de temps occasionnelle des PVS re-search. Dans la pratique, le premiercoup test est celui de la Hash Table (voir 2.2), s'il y en a un.

  • 2 AMLIORATIONS DE L'ALGORITHME 11

    2.2 Hash Tables

    2.2.1 Motivations

    Transpositions. L'exploration d'un arbre de coups aux checs, mme avec un algorithmePVS, est un calcul trs redondant. En eet, diverses trajectoires (de la racine aux feuilles) serecoupent, passant ainsi par les mme positions. Il serait donc bien pratique, lorsque l'on adj cherch la position courante la profondeur requise, de renvoyer directement le rsultatpralablement stock, ce qui permettrait d'laguer l'arbre d'avantage.

    Approfondissement itratif. Il existe aussi une autre bonne raison de stocker le travaileectu lors de la recherche : un programme joue avec une contrainte de temps, et pas de profon-deur. En eet, il est dicile de prdire qu'avec 10 secondes, il atteindra telle ou telle profondeurselon le niveau de complexit de la position. Il faut ncessairement augmenter la profondeur defaon itrative, en commenant disons par 2 (ce qui est toujours trs rapide). Ds qu'il ne resteplus de temps, il faut renvoyer le coup trouv la dernire profondeur explore entirement. Demanire assez contre-intuitive (voir [5]), chercher les profondeurs 2, 3, 4, 5 en remplissant au furet mesure une hash table, est plus rapide que de chercher directement la profondeur 5.

    2.2.2 Principe d'une Hash Table

    L'ide d'une hash table est assez simple : on stocke en mmoire tout ce que l'on calcule(position, profondeur, score et meilleur coup trouv). Enn, avant de chercher quelque positionque ce soit, on consulte la hash table, pour voir si la position n'a pas dj t cherche laprofondeur requise (ou plus loin). Cela permet d'viter le calcul redondant des transpositions :diverses trajectoires (de la racine aux feuilles) se recoupent souvent (i.e. passent par la mmeposition). Statistiquement, il a t montr que ce phnomne augmente avec la profondeur.

    D'un point de vue pratique, stocker et chercher une position doit tre une opration rapide etles entres d'une hash table doivent utiliser le moins de mmoire possible. Nous utilisons donc untableau, de taille 2N , avec recherche et insertion immdiates9. Cela suppose donc de disposerd'un ordre sur les positions : il faut construire une application aussi injective que possible qui une position associe un nombre, facilement manipulable en C++ : on appelle cela une signature.

    Il existe plusieurs algorithmes de signature gnriques (i.e. pour tout type de donnes), telsque CRC 32 ou MD5, utiliss typiquement pour vrier qu'un chier n'a pas t corrompu.Cependant, pour les programmes d'chec, il existe une mthode trs simple et plus spcique :les clefs de Zobrist sur 64 bits (voir [1]). Il s'agit, en eet, de la mthode utilise par tous lesbons programmes.

    2.2.3 Clef de Zobrist

    Il s'agit d'une mthode simple et ecace de signature des positions. L'ecacit signie,bien entendu, que la probabilit que deux positions distinctes aient mme clef de Zobrist estinme et peut tre nglige. Pour commencer, on remplit un tableau 3 entres (pice, case,couleur) par des nombres alatoires sur 64 bits :

    unsigned __int64 zobrist[piece][square][color]

    Partant de Z=0, on boucle sur les 64 cases en eectuant l'opration

    Z ^= zobrist[piece][square][color]

    ds que l'on rencontre une pice pice de couleur color sur la case numro square. Toujoursdans la mme ide, on gnre 64 nombres alatoires pour la case de prise en passant, 2 pour le

    9La position d'un clef est donn par ses N bits de poids faible.

  • 2 AMLIORATIONS DE L'ALGORITHME 12

    tour de jeu et 16 pour les 24 combinaisons possibles de permissions de roquer. De la mme faon,tout ce qui doit l'tre est mis dans la clef Z, base de l'opration XOR : et voila notre clef.

    Une proprit intressante des clefs de Zobrist est la possibilit des les calculer de faondynamique. Partant de la rgle de calcul

    (x ^ y) ^ y = x ^ (y ^ y) = x ^ 0 = x

    on peut mettre jour la clef, sans re-parcourir tout l'chiquier. Par exemple, partant de la positionde dpart de clef Z, aprs 1. e4, il n'y a qu' enlever le pion blanc de la case e2 pour le mettreen e4 :

    Z ^= zobrist[Pawn][E2][White] ^ zobrist[Pawn][E4][White]

    Il faut aussi mettre jour, de la mme faon, la permission de roquer, la case de prise en passant(dsormais e3) et le tour de jeu (c'est maintenant noir de jouer). Cependant, pour des raisonsde simplicit et de robustesse, nous n'utilisons pas cette astuce.

    2.3 Heuristiques d'lagage

    2.3.1 Null-move pruning

    Nous avons vu que le PVS permet de rduire sensiblement la taille de l'arbre explorer.Cependant, il ne s'agit pas d'une limite absolue d'lagage : il est possible d'aller plus loin, si l'ons'autorise quelques erreurs. Le null-move pruning est une mthode utilise avec beaucoup desuccs, dans tous les bons programmes d'checs modernes.

    Cet algorithme ne fait qu'appliquer un concept simple, que les joueurs humains utilisentnaturellement et sans le savoir. L'ide est la suivante : si vous choisissez de passer votre tour laissant l'adversaire jouer 2 coups conscutifs et que le score adverse est toujours mauvais,alors votre position est clairement suprieure. En termes plus prcis maintenant : si le joueur actifpasse son tour et le score adverse calcul une profondeur rduite d R est infrieur alpha,alors on renvoie simplement cette valeur, sans chercher exhaustivement le sous-arbre considr profondeur d. En fait, nous ne faisons que prdire un -cuto sans vraiment le vrier. BibiChessutilise cette mthode avec une rduction systmatique de R = 3 : nous avons pris la mme valeurque [7].

    Cependant, cette mthode peut s'avrer dangereuse dans les cas de zugzwang10. C'est pour-quoi BibiChess n'eectue pas de null-move lorsque le joueur actif n'a plus de pice, c'est--direjuste un roi et des pions. Cette condition de scurit est toutefois un peu faible. Les meilleursprogrammes prennent plus de prcautions, en ce qui concerne les null-move :

    1. la rduction de profondeur R augmente avec la profondeur du sous arbre chercher.

    2. cette mme rduction baisse lorsque l'on est en nale avance.

    3. ds qu'un -cuto est prdit par un null-move, on lance un algorithme de vrication dezugzwang connu sous le nom de verication search.

    An de ne pas alourdir l'expos, nous ne parlerons pas de cet algorithme, que BibiChess n'utilisepas.

    2.3.2 Delta pruning

    Le delta pruning est une mthode d'lagage approximatif, qui s'applique au niveau du quies-cent search. Nous n'avons pas trouv de rfrence thorique ce sujet, mais deux codes source[6] et [7], qui procdent tous les deux diremment. Nous avons choisi la mthode applique par[6]. Le delta pruning ne s'applique bien sr pas lorsque la position est un chec. Pour tous lesautres noeuds du quiescent search, on boucle sur les coups et :

    10On appelle ainsi, une position dans laquelle le joueur actif a intrt passer son tour ce qui n'est bien srpas possible. Ce phnomne se produit souvent en nale roi+pions.

  • 2 AMLIORATIONS DE L'ALGORITHME 13

    1. On eectue une valuation optimiste du quiescent search, en ajoutant le SEE du coup etl'valuation statique de la position.

    2. Si cette valeur trop faible, disons , alors on saute ce coup sans le dvelopperrcursivement.

    Nous avons choisi = 100 =p, ce qui est une valeur peu leve, donc un peu risque.

    2.3.3 Futility pruning

    Le futility pruning s'eectue un coup du quiescent search. L'ide est assez simple : s'il n'ya pas chec, le coup qui doit tre cherch n'est pas un coup tactique capture chec promotion, et le score actuel augment d'une certaine marge de scurit est , alors ce coup est trsprobablement mauvais. Dans ce cas, au lieu de le chercher profondeur 1, on le cherche profondeur 0, c'est--dire directement avec le quiescent search.

    Bien entendu, cette mthode n'est pas fonde thoriquement, et peut manquer des variantestactiques intressantes. En pratique, le gain apport par cette mthode compense largement cedfaut. Aprs tout, si l'on gagne disons une profondeur, alors on vite les erreurs tactiques liesau futility pruning et on gagne en tactique.

    La mthode s'tend au noeuds situs 2 coups du quiescent search. Le principe est le mme,mais cette fois, il faut prendre une marge de scurit plus importante. Si le score augment de lamarge de scurit est toujours , alors on rduit la profondeur de 1. Ainsi, au lieu de chercherle coup profondeur 2, on le cherche profondeur 1.

  • 3 IMPLMENTATION 14

    3 Implmentation

    Dans cette partie, nous ne prsentons pas tout le code, mais uniquement des morceaux choi-sis. Il s'agit en l'occurrence de la gnration des coups par la mthode des bitboard, ainsi quel'valuation positionnelle voque en 1.1.2.

    3.1 Les BitBoards

    3.1.1 Choix des structures

    Dans un premier temps, nous avons programm la gnration des coups d'une faon simpleet naturelle. Il s'agissait d'utiliser un tableau de 64 lments correspondant aux 64 cases del'chiquier. La gnration des coups se faisait ncessairement de la faon suivante :

    1. on boucle sur les 64 cases de l'chiquier.

    2. lorsque l'on trouve une pice (de la bonne couleur), on boucle sur l'ensemble de ses directionspossibles.

    3. enn, si la pice est une tour une dame ou un fou, il faut en plus boucler dans la directionconsidre en s'arrtant lorsque l'on rencontre une pice ou le bord de l'chiquier.

    Ainsi, nous avons 3 boucles imbriques ce qui est trs lent. Le mme schma se rpte d'ailleursdans l'valuation de la mobilit (voir 3.2.2). Il ne faut pas perdre de vue en eet, que le programmepasse la majeure partie de son temps dans la gnration des coups et dans l'valuation position-nelle. Nous avons ainsi obtenu une version de mi-parcours du programme, que nous avions appelNewbieChess cause de son faible niveau. An d'augmenter ses performances, mais aussi pourl'exercice technique de programmation, nous avons choisi de rcrire entirement la gnrationdes coups ainsi que l'valuation, en utilisant une mthode bien plus ecace et inniment pluslgante.

    BibiChess utilise une mthode sophistique pour la gnration de coups lgaux, ainsi que toutesorte de calculs relatifs l'chiquier. Il s'agit en gros, de reprsenter l'chiquier par des nombres 64bits, ce qui permet de faire toute sorte de choses avec des oprateurs bitwise, soit & | ^ ~ >.En particulier, des quantits de boucles sont vites, et tout simplement remplaces par des calculsimmdiats base d'oprateurs bitwise.

    3.1.2 Reprsentation de l'chiquier

    Commenons par le commencement, il faut d'abord numroter les cases de l'chiquier :

    A8 B8 C8 D8 E8 F8 G8 H8

    A7 B7 C7 D7 E7 F7 G7 H7

    A6 B6 C6 D6 E6 F6 G6 H6

    A5 B5 C5 D5 E5 F5 G5 H5

    A4 B4 C4 D4 E4 F4 G4 H4

    A3 B3 C3 D3 E3 F3 G3 H3

    A2 B2 C2 D2 E2 F2 G2 H2

    A1 B1 C1 D1 E1 F1 G1 H1

    56 57 58 59 60 61 62 63

    48 49 50 51 52 53 54 55

    40 41 42 43 44 45 46 47

    32 33 34 35 36 37 38 39

    24 25 26 27 28 29 30 31

    16 17 18 19 20 21 22 23

    8 9 10 11 12 13 14 15

    0 1 2 3 4 5 6 7

    Fig. 5 Numrotation des cases de l'chiquier

    ainsi que les pices et les couleurs :

    enum { White, Black };

    enum { Knight, Bishop, Rook, Queen, King, Pawn, Empty };

  • 3 IMPLMENTATION 15

    En clair, les cases sont numrotes de bas en haut et de gauche droite. Les ranges sontnumrotes de 0 7 (de bas en haut) et les colonnes de 0 7 (de gauche droite). Ainsi, pourtoute case A1 3

    nous donnent respectivement la colonne et la range de sq. Maintenant l'chiquier est reprsentpar des nombres 64 bits de la faon suivante :

    typedef unsigned __int64 U64;

    U64 Board::b[2][64];

    Chaque lment du tableau b doit tre considr comme un ensemble : les oprateurs & | ^ ~correspondent alors aux oprations ensemblistes d'intersection, de runion, de dirence sym-trique et de complmentation. Par exemple, b[White][Knight] reprsente l'ensemble des ca-valiers blancs sur l'chiquier, etc. . . Ainsi, la position de dpart, encode en notation bitboard,fait l'objet de la Fig. 6. Pour simplier les notations, nous utilisons un tableau pr calculU64 bit[64], dont le i-me lment est tout simplement bit[i] = U64(1)

  • 3 IMPLMENTATION 16

    int fsq, tsq; // from square, to square

    U64 fss = b[White][Knight], tss; // from squares, to squares

    while (fss)

    {

    next_bit(fsq, fss); // fsq parcours les cavaliers blancs

    tss = knight_moves[fsq] // cases atteignables par le cavalier considr

    & ~friends; // et qui ne contiennent pas de pices "amies"

    while (tss)

    {

    next_bit(tsq, tss); // tsq parcours les cases attaques par ce cavalier

    ... // gnrer ici le coup de cavalier fsq -> tsq

    }

    }

    Bien sr, c'est encore plus simple dans le cas du roi : il n'y a pas la boucle extrieure sur fss,puisque chaque joueur n'a qu'un seul roi.

    Pions. Pour gnrer les pousses de pions blancs d'une ou deux ranges, nous devons justeles avancer de 8 ou 16 cases, tant donn la numrotation choisie. Ainsi, avec le bitboard prcalcul rank_mask[8] correspondant aux ranges (numrotes de 0 7), voila comment nouspouvons gnrer les pousses de pions blancs :

    U64 fss = b[White][Pawn], tss; // from squares, to squares

    tss = (fss

  • 3 IMPLMENTATION 17

    Z Z Z ZZ o Z ZZ o Z ZJPZ Z ZS Z o jZ Z Z ZZ ZPsPZZ Z Z Z

    Z Z Z ZZ o Z ZZ o Z ZJPZ Z ZbA Z o jZ Z Z ZZ ZPZPZZ Z Z Z

    Fig. 7 Gnration des coups de tour ( gauche) et de fou ( droite).

    Concrtement nous avons, pour la tour en B4 (toujours sur la Fig. 7 gauche), nous avons :

    rank_slides[file(B4)][b01000101] = b10111100 = 0x3D

    Enn, il n'y a plus qu'a dcaler ce b10111100, pour le remonter sur la range 3. Plus gnralement,on a (avec des notation dsormais standard. . .) :

    tss = rank_slides[file(sq)][occupancy]

  • 3 IMPLMENTATION 18

    Diagonales. Toujours dans la mme ide, il faut rcuprer l'occupation de la diagonaleconsidre, et utiliser une table prcalcule. Cette fois, le problme se complique encore, puisqu'ily a deux types de diagonales (sens A1H8 ou A8H1) et qu'elles ont toutes des longeurs direntes,comme le montre la (Fig. 9).

    A1

    A2 B1

    A3 B2 C1

    A4 B3 C2 D1

    A5 B4 C3 D2 E1

    A6 B5 C4 D3 E2 F1

    A7 B6 C5 D4 E3 F2 G1

    A8 B7 C6 D5 E4 F3 G2 H1

    B8 C7 D6 E5 F4 G3 H2

    C8 D7 E6 F5 G4 H3

    D8 E7 F6 G5 H4

    E8 F7 G6 H5

    F8 G7 H6

    G8 H7

    H8

    A8

    B8 A7

    C8 B7 A6

    D8 C7 B6 A5

    E8 D7 C6 B5 A4

    F8 E7 D6 C5 B4 A3

    G8 F7 E6 D5 C4 B3 A2

    H8 G7 F6 E5 D4 C3 B2 A1

    H7 G6 F5 E4 D3 C2 B1

    H6 G5 F4 E3 D2 C1

    H5 G4 F3 E2 D1

    H4 G3 F2 E1

    H3 G2 F1

    H2 G1

    H1

    Fig. 9 Diagonales dans le sens A1H8 ( gauche) et A8H1 ( droite).

    Pour rcuprer l'occupation d'une diagonale, il nous faut donc le bitboard all_pieces re-numrot dans le sens A1H8 et A8H1, comme sur la Fig. 9. Toujours l'aide d'un dcalage et d'unltrage des bits de poids faible (>> et &), on rcupre les occupations voulues. Enn, les tablespr calcules suivantes nous donnent directement les to-squares tss que l'on cherche calculer :

    U64 diag_a1h8_slides[64][256], diag_a8h1_slides[64][256];

    On terminera donc par tss = diag_a1h8_slides[square][occupancy], aprs avoir calcul l'oc-cupation de la diagonale considre.

    Dans l'exemple de la gure Fig. 7 droite, pour gnrer les coups du fou blanc en B4, nousprocdons ainsi :

    1. les occupations des diagonales f8-b3 et a5-e1 sont b001010 et b11000.

    2. les bitboards prcalculs :

    diag_a1h8_slides[B4][b001010] et diag_a8h1_slides[B4][b11000]

    nous donnent alors les cases sur lesquelles le fou B4 peut aller.

    3.1.4 Acclration du gnrateur

    Implmentation Robuste. Pour gnrer les coups lgaux, la mthode la plus simple estde gnrer les coups pseudo-lgaux, de tous les jouer (et les dfaire), an de voir lesquels sontillgaux par auto-chec et lesquels mettent l'adversaire en chec. Nous avons en eet besoin desavoir directement quel coup donne chec, pour la partie tactique du code Computer::search qui eectue des extensions de recherche, voir 1.2.2. C'est ainsi que nous avons commenc, jusqu'ce que l'on prole le code pour s'apercevoir du temps perdu dans les fonctions Board::play,Board::undo et Board::in_check jouer, dfaire les coups et tester la mise en chec. Pour xerles ides, disons qu'avec 40 coups pseudo-lgaux dans une position donne, nous eectuions 40 foisplay et undo et 80 fois in_check. De mmoire, il me semble que la gnration des coups pseudo-lgaux n'occupait que 2.3% du temps de parcours d'un arbre moyen ! N'est-ce pas dommage dese casser la tte avec des bitboards pour tout gcher ainsi ?

    Actualiser dynamiquement ce qui doit l'tre. En se laissant guider par les rsultats duprole de Visual C++, nous avons vite compris que l'on perdait trop de temps dans le calcul

  • 3 IMPLMENTATION 19

    de la clef de Zobrist et des 3 transformes gomtriques de l'occupation globale de l'chiquier,soit all_pieces_sym, all_pieces_a1h8 et all_pieces_a8h1. En eet, chacun de ces calculsncessite une boucle de 64 itrations, et ce chaque utilisation de la fonction play soit environ40 fois plus que de noeuds (non terminaux) de l'arbre explor, d'aprs la remarque prcdente.Nous avons donc dcid de calculer dynamiquement la clef de Zobrist, voir 2.2.3 pour plusd'explications. De la mme faon, au lieu d'eectuer les transformations gomtriques sur toutle bitboard all_pieces, nous ne faisons que des actualisations concernant les bits eectivementdplacs. En tout et pour tout, cette amlioration multiplie, en moyenne, par 2.6 la vitessed'exploration d'un arbre de coup. Ce gain est d'autant plus apprciable qu'il est peu coteux, entermes de lignes de code supplmentaires.

    Filtrage des coups pseudo-lgaux. Jouer, tester deux fois la mise en chec et dfaire lescoups pseudo-lgaux, est une mthode bien trop laborieuse. Pour viter cette perte de temps,voila comment nous procdons :

    1. Si le joueur actif est en chec, nous utilisons l'implmentation robuste prcdemment d-crite. Seule une faible proportion des noeuds de l'arbre sont des checs. Ainsi, un codespcique pour ce cas n'est pas vraiment ncessaire. Cependant, les bons programmesd'chec disposent tous d'une fonction generate_check_escapes qui gnre directement lescoups lgaux lorsque l'on est en chec.

    2. Dans tous les autres cas, soit une immense majorit des noeuds de l'arbre, nous commenonspar calculer 2 bitboards : pinned_pieces et rvl_check, avec la fonction Board::find_pins.Il s'agit respectivement de l'ensemble des pices cloues et des pices pouvant rvler unchec dcouvert. A partir de l, nous bouclons sur les coups pseudo-lgaux :

    (a) Les prises en-passant et roques sont des cas particuliers, pour lesquels aucune optimi-sation n'est eectue. On utilise donc la mthode laborieuse (play, undo et in_check).N'oublions pas toutefois que ces coups sont trs rares dans l'arbre des coups.

    (b) Pour les coups de roi, on teste la lgalit avec un square_attacked(move.tsq,!turn),qui vrie directement si la case d'arrive est attaque par l'adversaire. La mise enchec de l'adversaire par un coup de roi (autre qu'un roque) ne peut rsulter qued'une attaque dcouvert, cache par le roi dplac. On teste donc si la case dedpart move.fsq appartenait rvl_check : si non alors pas d'chec, et si oui, alors lecoup est un chec si et seulement si le sort du rayon de clouage correspondant.

    (c) Pour les autres coups, c'est--dire le cas gnral, l'illgalit ne peut rsulter que d'unauto-chec dcouvert. En termes plus didactiques, un tel coup est lgal si et seulementsi la pice dplace n'est pas cloue ou bien si elle reste sur son rayon de clouage. Ence qui concerne la mise en chec de l'adversaire, un chec ne peut tre que direct ourvl11. Pour un chec direct, on regarde si le roi adverse est attaqu par la piceque l'on dpose12 sur la case d'arrive move.tsq. Pour un chec dcouvert, on testel'appartenance de move.fsq rvl_check : si non, le coup ne donne pas chec; si oui, lecoup donne chec si et seulement si move.tsq sort du rayon de clouage correspondant.

    Grce ce calcul des pices cloues et pouvant rvler un chec, nous avons encore gagn unfacteur 4.3 e, moyenne. Au total, les optimisations du gnrateur l'acclrent donc d'un facteur4.3 2.6 = 11.2 !

    11Ces deux cas ne sont pas mutuellement exclusifs : un chec la fois direct et rvl est prcisment un doublechec.

    12Qui est, en gnral la pice dplace. . . sauf en cas de promotion !

  • 3 IMPLMENTATION 20

    3.2 Evaluation positionnelle

    3.2.1 Introduction

    Aux checs, deux domaines sont gnralement distingus : la tactique et la stratgie. Alorsque la tactique correspond la capacit du joueur calculer exactement les squences de coupsgagnantes, la stratgie considre plutt la construction de long terme du jeu : dvelopper sespices et avancer selon un plan. Par plan, on entend aussi bien des choses simples, comme lecontrle du centre, que des choses plus compliques comme la construction d'une attaque sur leroi averse, ou changer les pices an de proter d'un avantage dans la structure de pion.

    L'un des buts de l'valuation, doit tre d'inciter la construction de plans crdibles, mais cen'est pas tout, l'valuation comprend nalement toute la culture chiquenne que va possder lemoteur. C'est notamment grce elle que le moteur va choisir comment dvelopper ses pices :par exemple, on peut attribuer un malus chacune des pices qui est reste la position initiale,et qui n'est donc pas dveloppe. Mieux, on peut attribuer un bonus lorsqu'une pice attaque lecentre, ainsi le moteur sera non seulement incit dvelopper ses pices, mais encore, il prfrerale faire de faon contrler le centre, vitant de placer ses cavaliers sur les bords de l'chiquier.

    La dicult majeure est de construire un ensemble de rgles, attribuant des bonus et desmalus, qui soit cohrent et le moins redondant possible. Dans l'exemple donn prcdemment,un coup de dveloppement de cavalier pourrait apporter un gain relatif la permission de roquerqu'il permet d'obtenir, un autre pour l'attaque du centre, et un malus s'il se trouve sur le bord.Et le gain nal prendra donc en compte chacune des rgles que l'on aura nonces au moteur.Il est donc essentiel de garder l'esprit les interactions entre ces rgles et d'essayer, autant quepossible de bien sparer les domaines an d'viter les incohrences et les redondances.

    3.2.2 Les composantes de l'valuation

    L'valuation que nous avons programm se dcoupe en trois domaines distincts : l'activitdes pices, la structure de pion et la scurit du roi.

    Concernant l'activit des pices, voici les lments principaux que nous valuons : La position d'une pice sur l'chiquier. Par exemple les cavaliers ne devraient pas tre surles bords, le roi prfre ne pas tre au centre sauf en n de partie, et les pions contrlantle centre sont apprcis.

    La mobilit des pices. On compte le nombre de cases non-attaques par les pions adversessur lesquels la pice pourrait venir, et pour chaque case on attribue un bonus relatif lapice.

    Les schmas. Ils correspondent l'interaction d'une pice avec d'autres, appartenant l'adversaire ou non. Cela comprend par exemple le fait d'avoir une tour bloque en H cause d'un roi en F et des trois pions en position initiale F,G,H. Mais aussi le fou blancbloqu en H7 par un pion adverse en G6.

    Le reste, qui ne correspond ni aux pions, ni au roi, mais que nous n'avons pas su classerdans les catgories prcdentes. Cela comprend par exemple le fait de placer une tour enseptime range ou sur une colonne ouverte.

    Nous pouvons dj voir que certaines de ces rgles entrent en conit ou sont redondantes :avoir une tour sur une colonne ouverte permet non seulement d'accrotre la mobilit de la tour,mais aussi d'obtenir le bonus spcique. Cela n'est pas un problme dans le cas prsent, puisquecela est identi, et l'on rduit donc simplement le bonus spcique puisque l'aspect mobilit surune colonne ouverte est dj pris en compte.

    Par structure de pion, nous entendons les pions doubls, isols (malus), candidats ou passs(bonus). Mais d'autres notions de la culture chiquenne pourraient mriter d'tre implmentes,tels que les pions faibles, arrirs, les les ou les chanes. Pour les pions passs, qui constituent le

  • 3 IMPLMENTATION 21

    but ultime pour un pion, l'valuation identie elle-mme si l'on peut considrer que la promotionne pourra tre empche. Cela n'est bien entendu ralis que dans les cas simples suivants :l'adversaire n'a plus d'autre pice que son roi et ses pions, et son roi n'est pas dans le carrdu pion, ou bien notre roi dfend la fois le pion et sa case de promotion. Dans les deux casla promotion est assure, et l'on peut attribuer un bonus aussi important que la valeur d'unedame moins celle du pion pass. Cela permet de plus dans ces cas spciques de gagner quelquesprofondeurs dans la vision du jeu, moindre frais.

    Dans la scurit du roi, nous avons comptabilis les attaques sur les cases adjacentes auroi, en n'attribuant des bonus que si plusieurs pices participent cette attaque. Aucun pointn'est attribu la dfense, par consquent, lorsqu'une attaque de l'adversaire lui procure tropde points, les seules rponses admises sont d'interposer ses pices, ou de capturer les picesattaquant le roi. Cette partie de l'valuation est la plus sensible et la plus dicile. Notre solutionest relativement douteuse, mais s'eorce de prendre en compte cet aspect du jeu.

    Finalement, nous ne devons pas perdre de vu que beaucoup de rgles sont spciques uncontexte positionnel, an de ne pas attribuer tort et travers ces bonus. Le plus importantd'entre eux tant ce que l'on nomme habituellement phase de jeu (ouverture, milieu de partie,nale). Entre autres, un roi positionn au milieu de l'chiquier est pnalisant l'ouverture maisbnque en nale; un pion pass a lui bien plus de valeur en nale qu'en ouverture. Le plusimportant est srement que la structure de pion doit tre d'autant plus prise en compte que l'onapproche de la nale.

    3.2.3 Les phases de jeu

    Concernant les phases de jeu, il n'existe aucun consensus sur leur dnition. Il nous a doncfallu en trouver une. Nous avions initialement dni ces phases de faon stricte et irrversible,et attribu uniquement les bonus relatifs la phase en cours. Cela pose un problme de conti-nuit dans l'valuation : si les bonus sont trs dirents d'une phase l'autre, le moteur avaitl'impression qu'un seul change lui permettait de passer dans la phase suivante, et pouvait ainsiamliorer nettement son valuation positionnelle sans que cela n'aie vraiment de sens pour lapartie en cours. De plus nous tions dsireux de construire des plans, or l'eet sus-cit ne le faitpas, vu son eet trs ponctuel.

    Une meilleure utilisation des phases de jeu, dont nous avons repris le principe dans le codesource de Fruit se base sur l'observation suivante : lorsque chaque joueur possde encore toutesses pices, alors nous sommes videmment dans l'ouverture; lorsque les joueurs n'ont plus que leurroi et des pions, alors il s'agit de la nale. On peut alors concevoir qu'entre ces deux situationsextrmes rien ne soit parfaitement identi, et que la meilleure faon de procder consiste utiliser une valuation pour l'ouverture, une valuation pour la nale, et en faire une sommepondre par la quantit de pices (autres que les pions) encore sur l'chiquier.

    D'une part cela vite les discontinuits d'valuation entre les phases, d'autre part cela vaajouter une dimension la stratgie du moteur. Il est dsormais capable d'identier qu'il atout intrt changer ses pices contre celles de l'adversaire, ds que sa structure de pion estmeilleure. En eet, ce faisant il va accrotre la pondration accorde l'valuation en contextenale, qui lui est encore plus favorable que celle du contexte ouverture. Dans cette situation,et mme aprs quelques changes, le moteur sera toujours dsireux de continuer changer lespices, s'assurant ainsi que sa structure de pion gagnante lui permettra de faire une promotion.

    Enn, n'oublions pas qu'il est extrmement dicile de provoquer l'apparition d'un compor-tement prcis. Les modications de l'valuation sont donc faire trs prcautionneusement etil est important de chercher observer leur eet par l'observation de nombreuses parties. Dansla mesure o l'valuation fait intervenir de nombreux paramtres, plus ou moins arbitraire, ilest essentiel de le faire an de choisir des valeurs raisonnables tenant compte de l'ensemble des

  • 3 IMPLMENTATION 22

    rgles. On pourrait aussi tre dsireux de rendre optimaux ces paramtres, l'aide d'une m-thode systmatique telle que les algorithmes gntiques. Il faut nanmoins garder l'esprit quel'valuation d'un niveau ELO (qui serait le critre optimiser) est une chose trs longue, rendantcette ide extrmement dicile mettre en pratique, voir impossible. De toute faon, dans unpremier temps, il est toujours nettement plus instructif d'avoir les commentaires d'un bon joueur,juste sur quelques parties.

  • 4 TESTS ET RSULTATS 23

    4 Tests et rsultats

    4.1 Validation du gnrateur de coups

    Le gnrateur de coups lgaux est assez dlicat coder, mais surtout dbuguer. Commetoujours, le code ne marche jamais du premier coup et le bug n'est pas o on l'attend. Il fautdonc procder avec mthode. Dans un premier temps, il faut s'assurer que dans tous les cas Board::undo dfait correctement ce que Board::play a fait. C'est d'abord dans cet unique but,que nous avons crit les fonctions d'import/export des positions en notation FEN. A cela, il fautajouter des tests la main pour chaque type de coups (dplacement, capture, chec, prise enpassant, roque, promotion).

    La preuve par Perft. Une fois les fonctions Board::play et Board::undo valides, il fauts'attaquer la gnration des coups lgaux. Nous avons d'abord dbug la main cette fonc-tion, et nous avons mme eu l'impression qu'elle marchait, jusqu' ce que nous entendions parlerde la fonction perft et du projet SMIRF [2]. La fonction perft est un talon, contre lequelon peut vrier son gnrateur de coups. Plus prcisment, le nombre de coups direntesprofondeurs et dans diverses positions a dj t calcul.

    rmblkansopopopopZ Z Z ZZ Z Z ZZ Z Z ZZ Z Z ZPOPOPOPOSNAQJBMR

    rZ ZkZ so oplpabm ZpmpZZ ZPM Zo ZPZ ZZ M ZQZpPOPABOPOS Z J ZR

    Z Z Z ZOPO Z ZkZ Z Z Z

    Z Z Z ZZ Z Z Z

    Z Z Z ZZ ZKopo

    Z Z Z Z

    Z Z Z ZZ o Z ZZ o Z Z

    JPZ Z ZrS Z o j

    Z Z Z ZZ ZPZPZ

    Z Z Z Z

    Z Z Z ZZ ZKZ ZZpZ Z Z

    o ZbZ sZ Z j Z

    Z Z Z ZZ Z Z Z

    ZqZ Z Z

    Z Z Z ZZ Z Z ZppZ Z ZpaZ Z j ZPZpOnZ ZZ Z Z ZPZ Z ZPOZrA ZRJ

    Fig. 10 Positions analyses par le projet SMIRF

    En particulier, les rsultats sont dcomposs en : captures, prise en-passant, chec, mat, pro-motion et roque. Les positions n'ont pas t choisies au hasard, mais pour couvrir tout l'ventaildes possibilits. Ce n'est que grce ces chires comparatifs que nous avons pu localiser quelquesbug rsiduels, lis gnralement la prise en passant ou au roque. Cette mthode systmatiqueest intressante, parce qu'il est dicile de tout envisager la main.

    4.2 Performances

    Nous avons eectu quelques test sur diverses positions, an de mesurer les amliorationsqu'apportent chaque composante de l'algorithme. Pour ne citer qu'une position, nous reprenons

  • 4 TESTS ET RSULTATS 24

    la Fig. 1. Plus prcisment, nous eectuons dans cette position une recherche profondeur 5 quidonne bien 14. Bg6 ! en activant progressivement les diverses composantes de l'algorithme :

    Algorithme Temps (sec.) Gain, standard 14.86 1

    + PVS 4.95 3.0

    + Hash Table 2.90 5.1

    + Null Move 2.01 7.4

    + Futility Pruning 1.73 8.6

    Ainsi dans la position considre, l'algorithme va 8.6 fois plus vite avec PVS + Hash Table+ Null Move + Futility Pruning, qu'un , standard. De plus, ce chire ne tient pas comptede l'amlioration essentielle apporte par le tri des coups utilisant le SEE : celui-ci est toujoursappliqu. Mme si nous ne l'avons pas chire prcisment, l'amlioration due au SEE nous asembl agrante ds que nous l'avons teste.

    Conclusion

    Finalement, notre programme rpond de faon satisfaisante au problme pos initialement. Ilsait en eet rsoudre des problmes tactiques, mais aussi avancer stratgiquement dans une partie.Cependant, BibiChess est loin d'tre parfait et beaucoup de choses peuvent tre amliores : lequiescent search, l'valuation, les algorithmes de pruning. Quoiqu'il en soit, le rsultat obtenuest plutt motivant, aussi nous continuerons dvelopper le programme par la suite.

    BibiChess est aujourd'hui disponible sur Internet www.uciengines.de et des listes ind-pendantes lui donnent un niveau d'environ 2 000 points elo.

  • A PR REQUIS 25

    A Pr requis

    A.1 Rgles du jeu

    Commenons d'abord par rappeler brivement les rgles du jeu. Les dplacements des picesseront supposs connus. Nous rappelons ici toutes les autres rgles, parfois mconnues :

    Le roque. Il y a deux roques possibles : petit roque (ct roi) et grand roque (ct dame).Pour pouvoir roquer, il faut que le roi et la tour concerne n'aient jamais bougs, que le roine soit pas en chec et qu'il ne passe pas par un chec pour roquer. Bien sr il faut aussique l'espace sparant le roi et la tour soit vide.

    La prise en passant. Apres une double pousse de pion, la case intermdiaire est captu-rable par un pion adverse au coup suivant (et seulement au coup suivant).

    La promotion. Ds qu'un pion arrive sur la dernire range, il se transforme en pice (auchoix : cavalier, fou, tour, dame).

    Fin normale du jeu. Le jeu s'arrte lorsque le joueur qui doit jouer n'a plus de coupslgaux : s'il est en chec il perd par chec et mat, sinon il est pat et la partie est nulle.La partie est aussi dclare nulle si aucun des deux joueurs n'a de matriel susant pourmater (par exemple, roi contre roi + cavalier).

    Fin de parties perptuelles. La rgle des 3 coups stipule que lorsqu'une position donnes'est retrouve 3 fois dans la partie, cette partie est nulle. De faon similaire, la rgle des 50coups dclare la partie nulle aprs 50 coups rversibles conscutifs : les coups irrversiblestant les captures et pousses de pions.

    A.2 Notation des coups

    Il existe essentiellement deux bonnes faons de noter les coups, selon l'utilisation qui en estfaite.

    Notation algbrique. La faon la plus simple de noter les coups sans ambigut est deconcatner la case de dpart et la case d'arrive. Il faut juste signaler, en cas de promotion, lapice choisie. Ainsi, un dbut de partie classique ressemble a : e2e4 c7c5, g1f3 d7d6 (. . .)e7e8q. Bref, ce genre de notation est facile gnrer informatiquement, mais dicile lire pourl'utilisateur. Ainsi, notre programme utilise cette notation dans le seul but de communiquer enbas niveau avec une interface (voir B), mais ache ses coups l'utilisateur en notation SAN.

    Notation SAN. C'est cette notation qui est utilise dans le prsent document. Il s'agit cettefois de concatner :

    1. la pice dplace {N,B,R,Q,K}2. un 'x' pour une capture

    3. la case d'arrive

    4. une indication en cas de promotion : '=Z' pour une promotion de pice Z {N,B,R,Q}5. un indicateur 'x' en cas d'chec, et '#' pour un chec et mat.

    Ainsi, le mme dbut de partie ressemble a : 1. e4 c5; 2. Nf3 d6 (. . .) 40. e8=Q+, cequi est bien plus parlant pour l'utilisateur. Dans certains cas, cette notation est ambigu. Parexemple, dans le cas de la Fig. 1, 14. Ne6 peut dsigner 14. Nf2e6 ou 14. Ng5e6. Onutilise alors les notations 14. Nfe6 ou 14. Nge6. De la mme faon, si les deux cavaliers nesont pas distinguables par leur colonne, mais par leur range, on utilise le numro de range.

    Enn, les roques sont nots O-O (petit roque) et O-O-O (grand roque). Bien sr, d'un pointde vue informatique, un coup SAN est une chane de caractre, donc les jolies icnesNBRQKsont remplaces par les vilaines abrviations NBRQK (kNight N, Bishop B, Rook R, Queen Q,King K).

  • B INTERFACE UCI 26

    A.3 Notation FEN des positions

    La position de l'chiquier est caractrise par : l'agencement des pices, le tour de jeu, les 4permissions de roquer, la case ventuelle de prise en-passant13. Par exemple, la position de laFig. 1 se note

    r1bn1rk1/pp2b2p/1q2pnp1/2pp2N1/3P1N2/2PB4/PPQ2PPP/R1B2RK1 w - -

    Il s'agit en eet, de lire l'chiquier de haut en bas et de gauche droite, de noter les pices (NBRQKpour blanc et nbrqk pour noir) et de compter les espaces vides d'o les chires qui apparaissent.Ensuite, le 'w' signie que c'est blanc de jouer. Enn, puisqu'il n'y aucune permission de roqueret pas de case de prise en passant (le dernier coup tant 13. . . . g6) '-' est rpt deux fois.Un dernier exemple (pour le roque et la prise en passant) : aprs 1. e4 dans la position initiale :

    rmblkansopopopopZ Z Z ZZ Z Z ZZ ZPZ ZZ Z Z ZPOPO OPOSNAQJBMR

    rnbqkbnr/

    pppppppp/

    8/

    8/

    4P3/

    8/

    PPPP1PPP/

    RNBQKBNR

    b KQkq e3

    Fig. 11 Exemple de notation FEN.

    e3 est bien sr la case de prise en passant et les quatre permissions de roquer sont au vert('KQ' pour le roque blanc ct roi et dame, idem pour noir en minuscules). En pratique cettenotation nous est trs utile, ne serait-ce que pour faire des copier-coller entre l'interface [4], lecode en C++ et le code LATEX de ce rapport (notations de coups et diagrammes).

    B Interface UCI

    B.1 Manuel de l'utilisateur

    Pour tester le programme avec une interface graphique, il faut :

    1. Tlcharger l'interface Arena [4] sur www.playwitharena.com

    Dans Arena Downloads (sur la gauche) choisir la version 1.1 setup2, et l'installer en franais.Au message demandant si l'on souhaite 'Set Nalimov Path...' rpondre 'Nein'.

    2. Dans Arena, faire Module => Nouveau Module => UCI.

    Slectionner le chier excutable du programme, le module portera le nom de ce chier.

    3. Dans Arena, faire Module => Grer.

    Dans l'onglet Choix, placer le module en premier module actif et faire Ok.

    Pour utiliser le livre d'ouvertures install par dfaut avec la version 1.1, il faut :

    1. Dans Arena, faire Biblio. => Grer.

    Dans l'onglet Donnes, faire Nouveau.

    Slectionner little-mainbook.abk

    13. . .ainsi que le numro du dernier coup et le compteur des 50 coups, mais passons.

  • B INTERFACE UCI 27

    2. Dans Arena, faire Modules => Grer.

    Dans l'onglet Dtails,

    slectionner le module qui porte le nom du chier excutable,

    Dans le sous-onglet (sur la droite) Bibliothques, cocher 'Utilise bibliothque, de Arenaavec ce module',

    faire Appliquer, puis Ok.

    Pour changer les options paramtrables du moteur, il sut de faire Ctrl+1 dans Arena. Toutemodication de ces options est mmorise pour la prochaine utilisation, mais elles peuvent trerinitialises leurs valeurs par dfaut.

    B.2 Le protocole UCI

    Le protocole UCI est simple manier, puisqu'il fonctionne par des entres/sorties en modetexte, c'est--dire base de cin >> et de cout option name Specimen type check default true // Puis dclare ses options paramtrables

    => option name Specimen2 type spin default 100 min 0 max 500

    => uciok // Mets fin aux prsentations

  • RFRENCES 28

    Rfrences

    [1] Cls de Zobrist : www.seanet.com/~brucemo/chess.htm page perso d'un certain BruceMoreland, que je remercie.

    [2] Projet SMIRF : calcul dtaills des premires valeurs de la fonction Perft, dans direntespositions, www.chessbox.de

    [3] Dnition du protocole UCI : www.shredderchess.com

    [4] Arena, une interface UCI gratuite : www.playwitharena.com

    [5] Chess Programming Theory : www.frayn.net/beowulf/theory.html

    [6] GNU Chess : http://ftp.gnu.org/pub/gnu/chess/

    [7] Fruit 2.1 : http://wbec-ridderkerk.nl/html/download.htm

    IntroductionPrincipe de l'IAL'algorithme minmaxExtensions tactiques

    Amliorations de l'algorithmeL'algorithme PVSHash TablesHeuristiques d'lagage

    ImplmentationLes BitBoardsEvaluation positionnelle

    Tests et rsultatsValidation du gnrateur de coupsPerformances

    ConclusionPr requisRgles du jeuNotation des coupsNotation FEN des positions

    Interface UCIManuel de l'utilisateurLe protocole UCI