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
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
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
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
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