Le déplacement du cavalier en VBA

Les coups du Cavalier depuis g1 : DynamicContext

Les coups du Cavalier depuis g1 : DynamicContext


En vue d’appeler prochainement le générateur de coups d’Echecs, initialisons les tables de déplacements des pièces.

Simulons manuellement le déplacement du Cavalier g1 en terme d’ordinal + d’offset.

Importer ModChess.bas

Si ce n’est pas déjà fait, vous pouvez archiver Chess.xls en Chess03.xls : voir Gestion de la sauvegarde du .xls et de ses modules .bas

Dans la fenêtre projet du VBE de Chess.xls, effacez uniquement le module ModChess.

Le fichier compressé ChessVba04.zip (20 Ko) contient 3 modules .bas et 5 modules de classe .cls dans le répertoire Source04. La feuille Excel Chess04.xls avec l’échiquier graphique n’est pas fournie. Seul le module ModChess a changé par rapport au précédent .zip

ChessVba04.zip

Rappel : Après un téléchargement sur Internet, passez systématiquement l’anti-virus avant et après le dézip.

Dans la fenêtre de projet du VBE, importez le seul module qui a changé à savoir ModChess.bas

VBE menu "Fichier" > "Importer fichier" (Ctrl+M). On considère que les autres modules y compris les modules de classes ont déjà été importés.

Vous pouvez archiver Chess.xls en Chess04.xls


Initialisation du jeu

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

DynamicContext

Cette procédure crée l’échiquier et initialise les tables pour le déplacement des pièces.

On a appelé cette procédure DynamicContext() parce qu’à la moindre modification de code ou en cas de bug, tout le contexte dynamique de l’échiquier peut se volatiliser de la mémoire comme si on avait débranché la prise de courant. C’est l’inconvénient de l’objet par rapport aux constantes publiques statiques. Les objets sont certes dynamiques mais volatiles c-a-d non persistants.

En pratique pour réinitialiser l’échiquier, on peut rappeller DynamicContext() autant de fois que l’on veut.


Principe du déplacement d’une pièce

Les huit offsets signés du Roi

Le principe du déplacement d’une pièce se fait en ajoutant, à son n° de case (ordinal), un déplacement signé (offset). Le déplacement d’une pièce peut être décrit par un tableau d’offsets.

  • Dans une première phase, on va simuler le coup du Cavalier manuellement.
  • Dans une seconde phase, on demandera au générateur de coup de faire la même opération.

Le déplacement du Cavalier

Les huit offsets signés du Cavalier

En se basant sur la figure des offsets du Roi, on peut calculer l’offset pour aller de g1 à e2.

Il faut d’abord un déplacement en diagonal (+15) plus un déplacement horizontal (-1) = +14

Quel est le nombre des offsets d’un Cavalier pour déterminer tous ses coups possibles ?

? UBound(offsetKnight)

8

Le Cavalier peut potentiellement bouger sur 8 cases. UBound() retourne l’Upper Bound d’un tableau, soit son indice maximum. On a quand même utilisé la constante nbrOffsetKnight = 8 pour éviter d’avoir à appeler UBound(offsetKnight) pour des raisons de performance.

Le premier offset de déplacement du Cavalier est :

? offsetKnight(1)

14

C’est l’addition de deux offsets (+15) + (-1) = +14 indiqués précédemment.

De la case de départ g1, où le Cavalier peut-il avancer ?

On additionne l’ordinal de sa case avec ce premier offset de Cavalier.

? boardMain.GetSquare(g1 + offsetKnight(1)) is Nothing

False

Il existe donc une case à l’arrivée pour cet offset de Cavalier.

? boardMain.GetSquare(g1 + offsetKnight(1)).Name

e2


La case d’arrivée e2 est occupée

Effectivement de g1, le Cavalier peut se déplacer en e2 si la case est vide ou s’il y a une pièce adverse, ce qui ne peut pas arriver en début de partie.

On utilise la méthode GetPiece() au lieu de GetSquare() pour récupérer la pièce sur la case.

? boardMain.GetPiece(g1 + offsetKnight(1)) is Nothing

False

Il y a une pièce en e2.

? boardMain.GetPiece(g1 + offsetKnight(1)).isWhite

True

C’est une pièce amie de la même couleur que le Cavalier.

? boardMain.GetPiece(g1 + offsetKnight(1)).Name

P

C’est le pion blanc du Roi.

Comme le Cavalier en g1 ne peut pas capturer son propre pion, on explore le prochain offset.


Coup suivant

Passons à l’offset suivant.

? offsetKnight(2)

-14

L’offset est donc signé. Intuitivement on se rend compte qu’un tel nombre négatif (supérieur en valeur absolue au nombre de cases dans une rangée) ajouté au n° de case va faire sortir le Cavalier de l’échiquier car il est déjà sur le bord de l’échiquier.

? boardMain.GetSquare(g1 + offsetKnight(2)) is Nothing

True

On sort de l’échiquier. Passons aux offsets suivants qui sortiront de l’échiquier jusqu’au 5eme.

? boardMain.GetSquare(g1 + offsetKnight(5)) is Nothing

False

Le déplacement du Cavalier Cg1 sur l'échiquier &H88

La case jaune de départ est en hexa :

? Hex(g1)

4A

On peut vérifier sur l’échiquier &H88 que la case verte d’arrivée en hexa est :

? Hex(g1 + offsetKnight(5))

69

C’est la case traditionnelle de sortie du Cavalier vers le centre.

? boardMain.GetSquare(g1 + offsetKnight(5)).Name

f3

? boardMain.GetPiece(g1 + offsetKnight(5)) is Nothing

True

La case est vide. Le Cavalier peut donc y jouer.


Initialisation des tables de déplacement des pièces

Dans la fenêtre d’Edition de ModChess, recherchez DynamicContext().

Sub DynamicContext()
    InitAttackingTable

Sa première instruction est l’appel de InitAttackingTable().

Cliquez sur InitAttackingTable pour mettre le point d’insertion de texte sur son nom.

Cliquez avec le bouton droit de la souris > Menu contextuel "Définition"

VBE scrolle automatiquement jusqu’à la définition de InitAttackingTable().

On commence par le déplacement du Roi, puis on a regroupé le déplacement en rangée et colonne de la Dame et de la Tour. On poursuit par les tables de déplacement et d’attaque sur une diagonale pour la Dame et le Fou. Vient ensuite le Cavalier :

    indOffset = 0: varOffset = Array(14, -14, 18, -18, 31, -31, 33, -33)
    For Each offsetDir In varOffset
        indOffset = indOffset + 1
        offsetKnight(indOffset) = offsetDir
        isKnightAttacking(offsetDiffOrdinal + offsetDir) = True
    Next

varOffset est un Variant, un type générique capable d’accepter tous les types tel qu’ici l’affectation avec un Array (tableau) où la liste des offsets sont séparés par une virgule, l’ensemble étant entre parenthèse.

L’initialisation de la table offsetKnight se fait à l’intérieur de la boucle For Next.

        offsetKnight(indOffset) = offsetDir

Cependant l’indice de boucle est précédé du nouveau mot clé Each.

    For Each offsetDir In varOffset

For Each demande une variable offsetDir de type Variant qui sera affectée à chaque itération par une des valeurs prises séquentiellement dans (in) le tableau varOffset.

Si vous voulez explorer cette boucle dans le débogueur, vous constaterez que lors de la première itération offsetDir vaut 14,

puis lors de la seconde itération -14, etc... jusqu’à -33.

On aurait pu remplacer cette initialisation en affectant chaque élément du tableau un par un.

    offsetKnight(1) = 14
    offsetKnight(2) = -14
    '...
    offsetKnight(8) = -33

C’est quand même plus court avec la boucle For Each offsetDir In varOffset. L’initialisation des tables de déplacement des pièces n’étant exécutée qu’une fois au tout début du programme d’Echecs, on privilégie un code court plutôt qu’optimisé.


Précédent : Chess VBA a de la classe

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

Posté le 30 juillet 2011 par Matt