1
0
MATER - Recherche de mat à partir d'une position donnée d'une partie d'échecs
MATER est un programme simple de recherche de mat, implémenté comme une commande MS-DOS. Etant donné 1° une position légale notée au format FEN, 2° la couleur qui a le trait et 3° un nombre de coups, le programme cherche un coup qui aboutit à un mat en un nombre de coups inférieur ou égal à la limite prescrite.
J'avais téléchargé il y a quelques mois le code source de ce programme, ainsi que la page de présentation au format HTM. Or je viens de constater que la page en question est devenue indisponible.
C'est pourquoi je me suis permis d'ajouter le code source et la page de présentation originale dans les sources de developpez.com.
Roland Chastain
J'ai réécrit la fonction FEN2Posit, puisqu'apparemment le problème venait de là. (A noter que pour alléger le code, j'ai supprimé le contrôle de la validité de la chaîne.) A présent le programme fonctionne correctement quel que soit le compilateur.
(*
converts a string representing a FEN position to an internal
representation.
*)
FUNCTION FEN2Posit(fen: strg80): boolean;
var
x, y, i, j: integer;
c: char;
begin
x := 1;
y := 8;
i := 1;
with Posit do
begin
while i <= Length(fen) do
begin
c := fen;
case Upcase(c) of
'P', 'N', 'B', 'R', 'Q', 'K':
begin
case c of
'p': Board[10 * (10 - y) + x + 1] := BlackPawn;
'n': Board[10 * (10 - y) + x + 1] := BlackKnight;
'b': Board[10 * (10 - y) + x + 1] := BlackBishop;
'r': Board[10 * (10 - y) + x + 1] := BlackRook;
'q': Board[10 * (10 - y) + x + 1] := BlackQueen;
'k': Board[10 * (10 - y) + x + 1] := BlackKing;
'P': Board[10 * (10 - y) + x + 1] := WhitePawn;
'N': Board[10 * (10 - y) + x + 1] := WhiteKnight;
'B': Board[10 * (10 - y) + x + 1] := WhiteBishop;
'R': Board[10 * (10 - y) + x + 1] := WhiteRook;
'Q': Board[10 * (10 - y) + x + 1] := WhiteQueen;
'K': Board[10 * (10 - y) + x + 1] := WhiteKing;
end;
Inc(x);
end;
'1'..'8':
begin
j := Ord(c) - Ord('0');
while j > 0 do
begin
Board[10 * (10 - y) + x + 1] := Blank;
Inc(x);
Dec(j);
end;
end;
'/':
begin
x := 1;
Dec(y);
end;
end;
Inc(i);
end;
if Board = BlackKing then KingCastle := true else KingCastle := false;
if Board = BlackRook then QueenRookCastle := true else QueenRookCastle := false;
if Board = BlackRook then KingRookCastle := true else KingRookCastle := false;
if Board = WhiteKing then KingCastle := true else KingCastle := false;
if Board = WhiteRook then QueenRookCastle := true else QueenRookCastle := false;
if Board = WhiteRook then KingRookCastle := true else KingRookCastle := false;
EnPassantSquare := None;
end;
result := true;
end;
Reste une chose bizarre que j'observe : ce qui est affiché dans la console varie d'une fois sur l'autre, avec le même exécutable et le même fichier de commande ! Tantôt tous les caractères sont bien en place, tantôt ils sont mal rangés (mais apparemment les valeurs internes du programme ne sont pas affectées).
Je n'ai observé ce phénomène que lorsque j'ai compilé avec Virtual Pascal. Avez-vous la moindre idée de ce qui pourrait expliquer cela ?
D'accord, c'est gentil d'avoir regardé. Cela restera un mystère mais heureusement ça n'a pas vraiment d'importance.
Je vais essayer de modifier le programme, de façon à en faire une unité, sans affichage, avec seulement une fonction qui renvoie le résultat trouvé. Avec une profondeur de trois coups, la recherche ne prend qu'une fraction de seconde. Voilà de quoi relever sensiblement le niveau d'un programme.
En attendant, j'apprends pas mal de choses en lisant ce code. Rien que dans la déclaration des types, on trouve déjà des idées intéressantes, je pense par exemple à l'usage qui est fait du type set of :
| Code : | Sélectionner tout |
1 2 3 | type squares = set of 1..120; tArraySquares = array[black..white] of squares; |
Tueur ne me plaît pas non plus, quoique ce soit le sens étymologique du mot "mat" (du moins d'après ce que je crois savoir). Peut-être Matador, qui est reçu en français, et qui est moins désagréable à entendre ?
L'interface de l'unité consiste en une seule fonction, dont les arguments correspondent aux paramètres de la ligne de commande acceptée par le programme original.
| Code : | Sélectionner tout |
1 2 3 4 5 6 | function SolveMate( const aPiecePlacement: string; const aActiveColor: char; const aMoveNumber: integer; const aComputeAllMoves: boolean ): string; |
J'ai donné un grand coup de chiffon dans l'unité Matador (raccourci le code d'une centaine de lignes, remplacé une grande partie des noms par des noms plus explicites). Le code est devenu plus lisible et compréhensible, même s'il reste encore un peu de travail à faire à l'intérieur des procédures.
J'ai complété le programme de test, en incluant tous les exemples de la documentation. Tout fonctionne !
C'est un bien joli programme je trouve, et j'espère encore y retravailler. Une prochaine étape pourrait être de supprimer les goto mais j'ai besoin de réfléchir à deux fois avant de m'y attaquer. Si quelqu'un d'autre veut y mettre la main ou simplement faire une suggestion, n'hésitez pas !
| Code : | Sélectionner tout |
WriteLn('b7a8' = SolveMate('b7/PP6/8/8/7K/6B1/6N1/4R1bk w KQkq -', 3, SEARCH_ALL_MOVES)); // TRUE
J'ai retravaillé mon adaptation du programme de V. Albillo. Le programme peut désormais être utilisé soit comme unité, soit comme bibliothèque dynamique.
Sur la technique utilisée pour le passage des chaînes de caractères à la DLL, voir cette discussion avec la solution proposée par Paul TOTH (et qui est celle que j'ai adoptée).
Il est à noter qu'il reste possible d'utiliser directement l'unité matercore.

