Un générateur de coups d’Echecs en VBA

Générer une Collection de coups : GenerateLazyMoves(), listOfMoves, movePlayer, While

Générer une Collection de coups : GenerateLazyMoves(), listOfMoves, movePlayer, While


Appelons le générateur de coup du Cg1.

Calculons la description des coups aux formats San (utilisé dans un .pgn) puis descriptif.

Un générateur de coups d’Echecs en Excel VBA

Le générateur de coups automatise dans une boucle les opérations de la session précédente.

Le résultat est une liste de coups. Quand on parle de liste, en VBA il faut penser Collection.

Dans la fenêtre d’Exécution immédiate (Ctrl+G) du VBE, copier-coller et valider par ENTER :

DynamicContext

La procédure DynamicContext() crée une Collection de coups dénommée listOfMoves.

Pour l’instant elle existe (Not Nothing) mais elle est vide.

? listOfMoves.Count

0

Il y a zéro coup dans la liste.

Appelons le générateur de coup pour le Cavalier avec comme paramètre listOfMoves :

boardMain.GetPiece(g1).GenerateLazyMoves listOfMoves

Un coup est Lazy (paresseux) tant qu’on n’a pas vérifié si le Roi n’est plus en échec après qu’une pièce de son camp a joué ce coup. Ce n’est pas réellement une histoire de paresse, c’est plutôt que le contrôle de la résolution de l’échec du Roi est coûteux.

Un Lazy coup devient légal si le Roi n’est pas en échec ou si ce coup résout l’échec. Quand un Roi est mat, cela signifie que dans la Collection des Lazy coups, aucun ne permet de sauver le Roi. Il n’y a plus un seul coup légal.

Combien de coups le générateur a-t-il généré dans la Collection ?

? listOfMoves.Count

2

Le générateur a trouvé deux coups de Cavalier à partir de g1.

Comme on est au tout début de la partie, le Roi Blanc ne peut pas encore être en échec. Ces deux Lazy coups sont donc légaux mais pour simplifier, on ne va pas tout de suite le vérifier.

Accédons au premier coup d’indice 1 dans la collection

Set movePlayer = listOfMoves(1)

On utilise la variable movePlayer déclarée Public dans le module ModChess essentiellement pour son utilisation dans la fenêtre d’Exécution immédiate.


Notation d’un coup

Affichons ce coup : vous pouvez taper cette ligne en vous aidant de l’autocomplétion après un "."

? movePlayer.PieceMoved.Name + movePlayer.SquareFrom.Name + "-" + movePlayer.squareTo.Name

Ng1-f3

A première vue, cela apparaît comme la simple concaténation de trois String. Cependant pour optimiser, on ne calcule la description d’un coup que si on veut l’afficher ou en phase de mise au point. Pour l’instant la description du coup est vide

? movePlayer.Description

Rien ne s’affiche.

movePlayer.PgnSanFormat True

La méthode PgnSanFormat() calcule la description du coup selon le format dit San utilisé dans les parties .pgn

Si le dernier paramètre de type Boolean est True, alors on résout l’ambiguïté potentielle de la case d’origine de la pièce quand deux pièces de même type appartenant au même joueur peuvent atteindre la même case. Ex : Cd2 et Cg1 pour la case d’arrivée Cf3. Dans ce cas là, la notation du coup au format San est Cg-f3 avec l’initiale de la case de départ.

? movePlayer.Description

Nf3

Il n’y a pas eu d’ambiguïté dans la position de départ du Cavalier.

? movePlayer.DescrFull

Ng1-f3

C’est la description complète du coup dans la notation dite descriptive qui n’a pas l’ambiguïté du format San utilisé dans les parties d’Echecs .pgn

Calculons également la notation du second coup de la liste sans résoudre d’éventuelle ambiguïté puisque dans la position de départ, il n’y en a pas.

listOfMoves(2).PgnSanFormat False

Pour des raisons de performance, on appelle PgnSanFormat() avec False comme paramètre de résolution d’ambiguïté. Car cette résolution est coûteuse. Ce n’est que lorsqu’on doit afficher un coup sur le GUI pour l’utilisateur final qu’on doit résoudre l’ambiguïté de la notation .pgn avec le dernier paramètre de PgnSanFormat() à True.

On a fait un utilitaire de debug pour afficher le contenu d’une liste de coups :

DgbMovesPrint listOfMoves

Move 1 : Nf3

Move 2 : Nh3


Réinitialiser la liste de coups

Vous pouvez effacer chaque coup de la liste de coups par :

listOfMoves.Remove 1

Le 1ere item de la liste a été effacée. Puis une seconde fois :

listOfMoves.Remove 1
? listOfMoves.Count

0

La liste de coups est à nouveau vide.


ClearListOfMove() et la boucle While Wend

Quand la liste de coups sera plus importante, l’effacement manuel sera trop long.

Dans la fenêtre d’Exécution immédiate, on pourra utiliser l’utilitaire :

ClearListOfMove

Les curieux pourront étudier cette courte procédure de ModChess.

Le fait d’avoir fait manuellement l’effacement des deux coups de Cavalier aidera dans la compréhension de la procédure qui fait la même chose mais dans une boucle.

En haut de la fenêtre d’Edition de ModChess, il y a deux listes déroulantes (listbox) appelées : "(General)" et "(Declarations)".

Sélectionner dans la listbox "(Declarations)" à droite, la 2ème procédure ClearListOfMove().

ClearListOfMove() efface la Collection des coups d'Echecs

Après avoir testé si la Collection listOfMoves existe via If Not ... Nothing, ClearListOfMove() introduit la nouvelle structure conditionnelle :

While condition

TAB Bloc d’instructions ’ à aligner avec une TAB de plus que la marge du While.

Wend

On boucle tant que [While] la condition listOfMoves.Count > 0 est True, autrement tant qu’il y a des coups dans la liste. Cela signifie que le Bloc d’instructions en particulier listOfMoves.Remove 1 doit à un moment donné impérativement faire évoluer la condition à False sinon c’est la boucle sans fin.

On reconnaît immédiatement ce bug. Le PC utilise 100% de la CPU à tourner à fond dans la boucle. Cela fait chauffer la CPU si cela s’éternise et la souris n’est plus aussi réactive.

  • En théorie on peut arrêter l’exécution de la macro dans Excel par Ctrl+PAUSE.
  • En pratique, on peut être amené à tuer l’application Excel avec le gestionnaire des tâches de Windows (Ctrl+Shift+Esc) et on perd toutes les modifications qui n’ont pas encore été sauvées.

En phase de développement, pensez à sauvegarder avant d’exécuter des boucles While non encore au point.

Bien évidemment il n’y a pas de bug dans ClearListOfMove().

A la fin du Bloc d’instructions quand on a libéré le coup de la mémoire par :

Set moveThis = Nothing

on tombe sur l’instruction Wend qui correspond au Next à la fin du Bloc d’instructions d’un For.

On boucle en posant à nouveau la question si la condition listOfMoves.Count > 0 est True.

S’il reste encore des coups à effacer, on entre à nouveau dans le Bloc d’instructions pour une nouvelle itération.

Si la condition listOfMoves.Count > 0 devient False, on saute tout le Bloc d’instructions et on se retrouve sur l’instruction suivante, après le Wend, qui est ici :

Set listOfMoves = Nothing

On libère la liste des coups de la mémoire.


Déboguer le générateur de coups plus en détail

Dans la fenêtre projet du VBE, double-cliquez sur le module de classe Piece.

Dans la listbox des procédures de VBE, sélectionner GenerateLazyMoves()

Placez un point d’arrêt dans la 1ere instruction :

    Select Case m_typePiece

Dans la fenêtre d’Exécution immédiate, recommencez l’appel du générateur de coups :

boardMain.GetPiece(g1).GenerateLazyMoves listOfMoves

Avancez en pas à pas principal ou détaillé (F8) [Step Into] selon le niveau d’exploration voulue.


Précédent : Le déplacement du cavalier en VBA

Suivant : Affichage des coups des Blancs en VBA

Posté le 3 août 2011 par Matt