VBA & l’échiquier 0x88

dimanche 17 juillet 2011
par  Matt
popularité : 11%

Représentation interne de l’échiquier linéaire &H88 : ordinal et offset.


Quelle représentation interne de l’échiquier pour optimiser le générateur de coups ?

On discute des précédents modèles : 2D du GUI d’Excel, 1D dans une String, puis on introduit le nouveau modèle linéaire dit 0x88.

L’échiquier 2D

Echiquier physique (GUI) en 2D

Alors que la 1ere représentation qui peut venir à l’esprit est de prendre comme modèle l’échiquier physique 2D en colonne et rangée, on a pu constater dans l’échiquier graphique du GUI d’Excel l’augmentation de complexité en particulier l’imbrication des boucles For Next par rangée puis par colonne.

? (indFile >= 8) or (indRank >= 8) or (indFile < 0) or (indRank < 0)

De plus la détection des cases en dehors de l’échiquier en fin de balayage de diagonale, rangée, et colonne pour les pièces à longue portée (Dame,Tour, Fou) nécessite des conditions multiples pour tester les limites.


La représentation linéaire dans une chaîne

Echiquier linéaire de type String

Il n’y a plus qu’un indice de 1 à 64 dans la représentation mono-dimensionnelle de la chaîne de caractère BoardBuild(). Cependant l’extraction du contenu d’une case par Mid() n’est pas assez performante. Le modèle une case = un caractère, c-a-d l’initiale de la pièce, n’est pas expansible. Le test des cases en dehors d’une rangée, colonne, diagonale n’est pas simple.


L’échiquier &H88

L’idée est de représenter les cases de l’échiquier toujours dans un tableau à une seule dimension mais plus grande qu’un échiquier. Le n° de case appelé ordinal est structuré pour avoir des propriétés qui facilitent la détection quand on sort de l’échiquier et les tests d’alignements indispensables pour savoir par exemple si une pièce est clouée.

Echiquier 0x88 linéaire 16 * 16 représenté dans une matrice 2D

Il existe plusieurs version de l’échiquier 0x88. On a choisi un tableau à une dimension 16*16 = 256. L’échiquier est centré dans la matrice. Ceci évite d’avoir un ordinal négatif.

Le nom de l’échiquier 0x88 = &H88 en VBA vient de la constante hexadécimale en langage C où le préfixe hexa est "0x". C’est un masque que l’on appliquera prochainement sur l’ordinal avec l’opérateur And pour savoir immédiatement si on est en dehors de l’échiquier.

Pour optimiser le générateur de coups, on n’hésite pas à avoir de nombreuses déclarations ou initialisations à faire une seule fois au début de l’exécution du programme d’Echecs. C’est ainsi que l’on va déclarer chaque case, colonne et rangée par des constantes même s’il n’y a pas d’usage immédiat.


Gestion de la sauvegarde du .xls et de ses modules .bas

Archivez Chess.xls en Chess01.xls et exportez le module ModChess dans le fichier ModChess.bas :

  • Sélectionner ModChess dans la fenêtre projet du VBE.
  • Bouton droit de la souris > Menu contextuel "Exporter le fichier" ([bleu marine]Export File[/bleu marine]).

En phase de développement il est recommandé avant de sauver ou d’exécuter une feuille de calcul .xls d’exporter manuellement ses modules .bas. En cas de problème de sauvegarde ou lors d’un bug par exemple de saturation mémoire, Excel peut planter (c’est rare mais cela peut arriver). On risque de perdre les dernières modifications dans un module.

De plus pour limiter l’expansion de la taille du .xls (à partir de 300 ko), il peut être utile d’exporter chaque module, de les effacer, puis de les réimporter.

La gestion de la sauvegarde en Chess01.xls, Chess02.xls, etc... par fenêtre glissante de l’indice de sauvegarde (effacer une des anciennes versions obsolètes quand on en ajoute une nouvelle version) permet d’avoir un historique et de revenir en arrière si nécessaire ou pour comparaison.


Les constantes de ModChess

Maintenant que Chess.xls a été archivé, vous pouvez sélectionner l’ensemble des lignes de code du module ModChess et les effacer car on repart sur une nouvelle base. Bien sûr on conserve la feuille de calcul avec son échiquier graphique.

Définissons les constantes du nouveau module ModChess dans la fenêtre d’édition (scroller verticalement pour voir les nouvelles !) :

Option Explicit

Public Const colBoardMain = 14
Public Const rowBoardMain = 9

Public Const countRank As Byte = 8
Public Const countFile As Byte = 8

Public Const ascRank0 As Byte = 48
Public Const ascRank1 As Byte = 49
Public Const ascFileA As Byte = 97
Public Const ascFileH As Byte = 104

Public Const colorFillBeige = 40

Public Const strGameStartPosition = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"

Public Const a8 As Byte = &HB4, b8 As Byte = &HB5, c8 As Byte = &HB6, d8 As Byte = &HB7
Public Const a7 As Byte = &HA4, b7 As Byte = &HA5, c7 As Byte = &HA6, d7 As Byte = &HA7
Public Const a6 As Byte = &H94, b6 As Byte = &H95, c6 As Byte = &H96, d6 As Byte = &H97
Public Const a5 As Byte = &H84, b5 As Byte = &H85, c5 As Byte = &H86, d5 As Byte = &H87
Public Const a4 As Byte = &H74, b4 As Byte = &H75, c4 As Byte = &H76, d4 As Byte = &H77
Public Const a3 As Byte = &H64, b3 As Byte = &H65, c3 As Byte = &H66, d3 As Byte = &H67
Public Const a2 As Byte = &H54, b2 As Byte = &H55, c2 As Byte = &H56, d2 As Byte = &H57
Public Const a1 As Byte = &H44, b1 As Byte = &H45, c1 As Byte = &H46, d1 As Byte = &H47

Public Const e8 As Byte = &HB8, f8 As Byte = &HB9, g8 As Byte = &HBA, h8 As Byte = &HBB
Public Const e7 As Byte = &HA8, f7 As Byte = &HA9, g7 As Byte = &HAA, h7 As Byte = &HAB
Public Const e6 As Byte = &H98, f6 As Byte = &H99, g6 As Byte = &H9A, h6 As Byte = &H9B
Public Const e5 As Byte = &H88, f5 As Byte = &H89, g5 As Byte = &H8A, h5 As Byte = &H8B
Public Const e4 As Byte = &H78, f4 As Byte = &H79, g4 As Byte = &H7A, h4 As Byte = &H7B
Public Const e3 As Byte = &H68, f3 As Byte = &H69, g3 As Byte = &H6A, h3 As Byte = &H6B
Public Const e2 As Byte = &H58, f2 As Byte = &H59, g2 As Byte = &H5A, h2 As Byte = &H5B
Public Const e1 As Byte = &H48, f1 As Byte = &H49, g1 As Byte = &H4A, h1 As Byte = &H4B

Public Const fileA As Byte = &H4, fileB As Byte = &H5, fileC As Byte = &H6
Public Const fileD As Byte = &H7, fileE As Byte = &H8, fileF As Byte = &H9
Public Const fileG As Byte = &HA, fileH As Byte = &HB

Public Const rank1 As Byte = &H4, rank2 As Byte = &H5, rank3 As Byte = &H6
Public Const rank4 As Byte = &H7, rank5 As Byte = &H8, rank6 As Byte = &H9
Public Const rank7 As Byte = &HA, rank8 As Byte = &HB

Public Const pawnWhiteAttackRightOffset = 17
Public Const pawnWhiteAttackLeftOffset = 15
Public Const pawnBlackAttackRightOffset = -15
Public Const pawnBlackAttackLeftOffset = -17

Les fonctions de conversion de ModChess

Pour convertir l’ordinal ordSqr ([bleu marine]ordinal of the square[/bleu marine]) en File et Rank, on retrouve les mêmes opérations que l’on a vues dans l’article précédent : Partir sur une nouvelle base en VBA.

Rank est le poids fort de l’ordinal ordSqr. On n’a pas pu éviter la division entière de l’ordinal car le shift de 4 bits vers la droite n’existe pas de base en VBA.

File est le poids faible de l’ordinal ordSqr. On applique le And logique plutôt que le modulo.

Function RankFromOrdinal(ByVal ordSqr As Byte) As Byte
   RankFromOrdinal = ordSqr \ 16
End Function

Function FileFromOrdinal(ByVal ordSqr As Byte) As Byte
   FileFromOrdinal = ordSqr And &HF
End Function

Function OrdinalFromFileRank(ByVal indFile As Byte, ByVal indRank As Byte) As Byte
   OrdinalFromFileRank = indRank * 16 Or indFile
End Function

Function OrdinalToString(ByVal ordSqr As Byte) As String
Dim indRank As Byte, indFile As Byte

   indRank = RankFromOrdinal(ordSqr)
   indFile = FileFromOrdinal(ordSqr)
   OrdinalToString = Chr(ascFileA + indFile - FileA) + CStr(indRank + 1 - Rank1)

End Function

Public Function FileFromName(ByVal strNameFile As String) As Byte
Dim indFile As Byte

   indFile = Asc(strNameFile) - ascFileA + fileA
   If indFile < fileA Or indFile > fileH Then
       FileFromName = 0
   Else
       FileFromName = indFile
   End If
End Function

Public Function RankFromName(ByVal strNameRank As String) As Byte
Dim indRank As Byte

   indRank = Asc(strNameRank) - ascRank1 + rank1
   If indRank < rank1 Or indRank > rank8 Then
       RankFromName = 0
   Else
       RankFromName = indRank
   End If
End Function

Function FileToString(ByVal indFile As Byte) As String
   FileToString = Chr(ascFileA + indFile - fileA)
End Function

Function RankToString(ByVal indRank As Byte) As String
   RankToString = Chr(ascRank1 + indRank - rank1)
End Function

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

? "0x" + Hex(e5)

0x88

La case centrale e5 est également le nom de la représentation de l’échiquier 0x88 !


Conversion vers File

? FileFromOrdinal(e5)

8

Représentation interne de fileA à fileH.

? FileFromName ("e")

8

Cette conversion sera utile pour lire la liste de coups dans un fichier .pgn

? FileFromOrdinal(e5) - fileA

4

Représentation interne indFile de 0 à 7.


Conversion vers Rank

? RankFromOrdinal(e5)

8

Représentation interne de rank1 à rank8.

? RankFromName("5")

8

Cette conversion complémentaire à FileFromName() servira pour lire la liste de coups dans un fichier .pgn

? RankFromOrdinal(e5) - rank1

4

Représentation interne indRank de 0 à 7


Conversion de l’ordinal en coordonnées pour l’utilisateur final (GUI)

? FileToString(FileFromOrdinal(e5))

e

Coordonnée de colonne pour l’affichage sur le bord de l’échiquier ou dans un coup.

? RankToString(RankFromOrdinal(e5))

5

Coordonnée de rangée pour l’affichage sur le bord de l’échiquier ou dans un coup.

? OrdinalToString(e5)

e5

Coordonnée d’une case centrale pour l’affichage d’un coup.


Offset et différence d’ordinaux

Les huit offsets signés

Un offset est ce qu’on ajoute à un ordinal pour se déplacer d’une case dans une des huit directions comme le ferait un Roi.

Déplacement vertical d’un tour de 7 cases de a1 à a8

? OrdinalToString (a1 + 7 * 16)

a8

On ajoute à l’ordinal a1 la multiplication du nombre de cases par l’offset +16 de déplacement vertical.

Calculons la différence de deux ordinaux :

? (g8 - a1) mod pawnWhiteAttackRightOffset = 0

False

Les cases a1 et g8 ne sont pas alignées sur une même diagonale à 45°.

Une propriété intéressante de l’échiquier 0x88 est que la différence de deux ordinaux alignés est un multiple d’un offset.

? (h8 - a1) mod pawnWhiteAttackRightOffset = 0

True

Les cases a1 et h8 sont alignées sur une même diagonale à 45°.


Précédent : Partir sur une nouvelle base en VBA

Suivant : Concevoir un jeu d’Echecs 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