Concevoir un jeu d’Echecs en VBA

lundi 18 juillet 2011
par  Matt
popularité : 15%

Première architecture en terme d’échiquier, joueur, pièce et case : Type, With, "."


Comment aborder la conception d’un jeu d’Echecs ?

On peut concevoir une architecture autour de quatre notions : l’échiquier, la case, la pièce et le joueur.

Architecture du jeu d’Echecs : approche statique

Modèle statique du jeu d'Echecs

Partons de l’échiquier Board qui sera la racine de notre architecture. Détaillons chacun de ses champs :

Un Board c’est d’abord un tableau de cases : arrSquare(). On utilise le préfixe "[bleu marine]arr[/bleu marine]" ([bleu marine]array[/bleu marine]) pour le distinguer d’une Function qui a également des parenthèses en fin de nom mais pour la liste de ses paramètres.

Il y a deux joueurs playerWhite et playerBlack. Le joueur qui a le trait est playerToPlay.

Sur la feuille de partie papier, on trouve le n° de coup turnNo et la liste des coups movesHistory.

En VBA on parle de collection plutôt que de liste.

La collection movesRedoList servira pour sauvegarder les coups supprimés de movesHistory quand on navigue en sens inverse vers le début de la partie.

isGameOver pose la question la partie est-elle terminée ?

Le résultat final de la partie est dans resultGame.

La position de départ de la partie est au format FEN dans le cas où le PGN commencerait dans une position donnée.

Revenons sur le tableau de cases : arrSquare(256) :

On indique la dimension maximum (16 * 16 voir L’échiquier &H88) entre parenthèses. Le 1er élément du tableau a pour indice 0.

Une case a un n° appelé ordinal dont on déduit les coordonnées fileSqr et rankSqr.

La couleur de la case ne sert pas que pour l’échiquier GUI. Elle est utile pour identifier la couleur des Fous.

Sur une case, on place une piece.

Une piece a un type : Roi, Dame, Tour, Fou, Cavalier, Pion.

Une piece a une couleur isWhite = True pour Blanche, False pour Noire.

Une piece appartient au joueur player qui a pour adversaire opponent.

Une piece est sur une case que l’on identifie par un ordinal.

Finalement un joueur Player a une couleur isWhite, la collection de ses pièces colPieces et des pièces adverses capturées colCaptures.

La caractéristique d’un joueur est le déplacement de ses pions en terme d’offset à ajouter à l’ordinal de la case de départ du pion.

Finalement le dernier champ d’un Player est : Le Roi de ce joueur a-t’il roqué hasCastled ?


Type de pièces, leurs valeurs, type de coups et résultat du jeu

Ajoutons de nouvelles constantes dans le module ModChess montrant que le projet se concrétise progressivement :

Public Const typeKing As Byte = 1
Public Const typeQueen As Byte = typeKing + 1
Public Const typeRook As Byte = typeQueen + 1
Public Const typeBishop As Byte = typeRook + 1
Public Const typeKnight As Byte = typeBishop + 1
Public Const typePawn As Byte = typeKnight + 1

Public Const valuePawn = 100
Public Const valueKnight = 300
Public Const valueBishop = 325
Public Const valueRook = 500
Public Const valueQueen = 975
Public Const valueKing = 1000

Public Const moveTypeNull As Byte = 0
Public Const moveStandard As Byte = moveTypeNull + 1
Public Const movePromotionQueen As Byte = moveStandard + 1
Public Const movePromotionRook As Byte = movePromotionQueen + 1
Public Const movePromotionBishop As Byte = movePromotionRook + 1
Public Const movePromotionKnight As Byte = movePromotionBishop + 1
Public Const moveEnPassant As Byte = movePromotionKnight + 1
Public Const moveCastleQueenSide As Byte = moveEnPassant + 1
Public Const moveCastleKingSide As Byte = moveCastleQueenSide + 1

Public Const statusNormal As Byte = 1
Public Const statusInCheck As Byte = statusNormal + 1
Public Const statusDrawStaleMate As Byte = statusInCheck + 1
Public Const statusInCheckMate As Byte = statusDrawStaleMate + 1

Public Const strAbbreviationPiecesEn = "KQRBNP"
Public Const strAbbreviationPiecesFr = "RDTFCP"

Définir une constante par incrément de la précédente constante nommée permet d’insérer une nouvelle constante où on veut sans devoir renuméroter les anciennes.


Implémentation VBA du modèle statique du jeu d’Echecs

Le codage de l’architecture statique du jeu d’Echecs peut se faire avec des types utilisateurs ([bleu marine]user defined type[/bleu marine]), c-a-d définis par le développeur grâce au mot-clé Type ... End Type.

Dans la fenêtre projet du VBE, cliquez avec le bouton droit de la souris sur "Modules" ou "ModChess", contextuel menu "Insérer" > "Module".

Dans la fenêtre "Propriétés", renommer "Module1" en "ModBoard".

Dans la fenêtre d’Edition de ModBoard :

Option Explicit
Const board0x88Height = 16
Const board0x88Width = 16

Type PlayerType
   isWhite As Boolean
   colPieces As Collection
   colCaptures As Collection
   PawnForwardOffset As Integer
   PawnForward2Offset As Integer
   PawnAttackRightOffset As Integer
   PawnAttackLeftOffset As Integer
   hasCastled As Boolean
End Type

Type PieceType
   typePiece As Byte
   isWhite As Boolean
   player As PlayerType
   opponent As PlayerType
   ordinal As Byte
End Type

Type SquareType
   ordinal As Byte
   fileSqr As Byte
   rankSqr As Byte
   isWhite As Boolean
   piece As PieceType
End Type

Type BoardType
   arrSquare(board0x88Height * board0x88Width) As SquareType
   playerWhite As PlayerType
   playerBlack As PlayerType
   playerToPlay As PlayerType
   turnNo As Integer
   movesHistory As Collection
   movesRedoList As Collection
   isGameOver As Boolean
   resultGame As Integer
   strFENStartPosition As String
End Type

Public boardMain As BoardType

Après la déclaration des nouveaux types, on déclare la variable boardMain de type BoardType.

C’est la première fois que l’on déclare une variable à l’extérieur d’une Function ou Sub.

Qui dit à l’extérieur dit que la variable n’est pas locale à une procédure. La variable est donc globale ce qui nous permettra de l’utiliser dans la fenêtre d’Exécution immédiate même après l’exécution de la procédure d’initialisation NewGame() :


Initialisation de la structure globale boardMain

Sub NewGame()
Dim ordSqr As Byte ' ordinal

   ' Le joueur des Blancs
   boardMain.playerWhite.isWhite = True
   boardMain.playerWhite.PawnForwardOffset = 16 ' e2-e3
   boardMain.playerWhite.PawnForward2Offset = 32 ' e2-e4
   boardMain.playerWhite.PawnAttackRightOffset = pawnWhiteAttackRightOffset
   boardMain.playerWhite.PawnAttackLeftOffset = pawnWhiteAttackLeftOffset
   
   ' Initialisation des 64 cases
   For ordSqr = a1 To h8
       If ((ordSqr - a1) And &H88) = 0 Then
           With boardMain.arrSquare(ordSqr)
               .ordinal = ordSqr
               .fileSqr = FileFromOrdinal(ordSqr)
               .rankSqr = RankFromOrdinal(ordSqr)
               .isWhite = (.fileSqr And 1) Xor (.rankSqr And 1)
           End With
       End If
   Next
   
   ' Création des huit pions des Blancs
   For ordSqr = a2 To h2
       With boardMain.arrSquare(ordSqr).piece
           .ordinal = ordSqr
           .isWhite = True
           .player = boardMain.playerWhite
           .opponent = boardMain.playerBlack
           .typePiece = typePawn
       End With
   Next
End Sub

On constate la répétition du préfixe "boardMain.playerWhite" pour chacun des champs du joueur des Blancs tel que sa couleur, l’avance d’un pion d’une case puis de deux cases, etc. Il est plus rapide en terme d’exécution de factoriser ce préfixe grâce à l’instruction With .. End With.

Dans la fenêtre d’Edition, remplacez l’initialisation du joueur Blanc par :

   With boardMain.playerWhite
       .isWhite = True
       .PawnForwardOffset = 16 ' e2-e3
       .PawnForward2Offset = 32 ' e2-e4
       .PawnAttackRightOffset = pawnWhiteAttackRightOffset ' e4xf5
       .PawnAttackLeftOffset = pawnWhiteAttackLeftOffset ' e4xd5
   End With

A l’intérieur du bloc With ... End With, chaque champ commence maintenant directement par le "." séparateur.

Aller à la fin du commentaire ’ e4xd5 et tapez ENTER pour créer une ligne vide.

Tapez deux TAB, pour s’aligner sur les précédentes instructions.

Expérimentez l’autocomplétion en ajoutant manuellement avant End With : le Roi des Blancs n’a pas encore roqué :

       .hasCastled = False
   End With

Saisir le "." plutôt que de faire un copier-coller.

Puis la première lettre "h" : hasCastled est sélectionné dans l’info-bulle.

Puis "=" le symbole d’affectation. HasCastled s’affiche tout seul suivi du "=".

L’autocomplétion propose False / True en info-bulle.

Choisir False avec flèche vers le bas. Valider par ENTER ou SPACE.

Notez que VBA va automatiquement insérer un espace blanc séparateur autour du "=".


Test hors rangée avec l’échiquier &H88

Dans l’initialisation des 64 cases dans le tableau boardMain.arrSquare(ordSqr), on retrouve le And avec la constante &H88 de l’échiquier 0x88.

Dans la fenêtre d’Exécution immédiate :

? ((h1 - a1) And &H88) = 0

True

h1 est bien sur l’échiquier.

? ((h1 + 1 - a1) And &H88) = 0

False

Dans le balayage horizontal d’une case vers la droite (offset +1), la Tour ne doit pas sortir de la première rangée au-delà de h1. Le test ((ordSqr - a1) And &H88) = 0 est peut-être moins parlant que (indFile >= 8) or (indRank >= 8) or (indFile < 0) or (indRank < 0) mais il est plus efficace.


Le premier pion blanc en a2

Lors de la création des huit pions dans la boucle For ordSqr = a2 To h2, dans le bloc par pièce With boardMain.arrSquare(ordSqr).piece, l’appartenance à un joueur .player = boardMain.playerWhite pose question. Car cette affectation va copier tous les champs du playerWhite. Une fois que l’on aura initialisé toute la structure globale boardMain, que peut-on en faire ?

Dans la fenêtre d’Exécution immédiate :

NewGame

Aucun résultat ne s’affiche car c’est une Sub.

? boardMain.arrSquare(a2).piece.typePiece

6

C’est le type d’un pion. Retrouvons son initiale :

? Mid(strAbbreviationPiecesEn, boardMain.arrSquare(a2).piece.typePiece, 1)

P

L’intérêt pédagogique est plus de saisir manuellement l’expression plutôt que de la copier-coller pour apprendre à utiliser l’autocomplétion quand on tape le séparateur "." avec ses propres types utilisateurs. Voir ci-dessus la saisie de hasCastled et, au tout début, Initiation à Excel VBA : la fenêtre Exécution.


En conclusion, on a décrit un modèle statique du jeu d’Echecs. L’utilisation de Types utilisateurs a permis de définir une première approche des champs de l’échiquier, joueur, pièce et case.

Pour rendre dynamique le modèle, il faudrait pouvoir lui intégrer des actions comme générer la collections des coups dans une position donnée ou jouer un coup et donc gérer la collection des pièces du joueur et des pièces capturées.


Précédent : VBA & l’échiquier 0x88

Suivant : Paradoxe de la gallinacée et de l’œuf en VBA


Brèves

Championnat jeunes 2018

dimanche 25 février 2018

A St Sernin sur Rance, Vadim Breton se qualifie pour le championnat de France jeunes. Il termine à la 4ème place des benjamins. http://echecs-occitanie.com/spip.php?article382&mode=AF

Les Jeunes qualifiés en NIII !

mercredi 14 décembre 2016

Dimanche 11 décembre 2016, aux interclubs jeunes à Leguevin, notre équipe a gagné un match et fait match nul aux deux autres.

L’équipe composée de Xavier, Vadim, Aurélie et Titouan termine 8ème et se qualifie pour la N3. A noter que Xavier et Vadim ont gagné toutes leurs parties.

Sur le Web : Site de la LMPE

Championnat jeunes

lundi 5 décembre 2016

Xavier, Vadim et Martin trois champions du Tarn et Garonne
Lire l’article

Coupe Loubatière

lundi 5 décembre 2016

Le club qualifié pour la phase régionale de la coupe Loubatière
Lire l’article

Sur le Web : Coupe Loubatière

Tournoi interne 2016-2017

lundi 5 décembre 2016

C’est reparti pour le tournoi interne : 1 partie par mois de novembre à mai
Lire l’article

Live Playchess.com

mercredi 7 septembre 2016