IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Contribuez Pascal Discussion :

Feuerstein, moteur de jeu d'échecs de Fritz Grau


Sujet :

Contribuez Pascal

  1. #41
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 624
    Par défaut
    Bonjour anapurna,

    Citation Envoyé par anapurna Voir le message
    Petite correction pour eviter de se retrouver avec un truc bizarre
    Tu as raison même si le Trim devrait s'appliquer avant le pos genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
       s := Trim(s);
       i := Pos(' ', s);
    En fait, je suppose - sans l'avoir vérifié - qu'un Trim(S) doit avoir lieu avant le premier appel parce qu'il est inutile ensuite. En effet, la chaîne est découpée en deux morceaux nettoyés : le mot avant la clé et le reste de la chaîne après la clé. Par ailleurs, il n'est pas nécessaire de faire un trim sur ces parties car il suffit de nettoyer juste à l'endroit de la coupure donc à droite pour le premier morceau et à gauche pour le second. C'est plus rapide.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    function GetKey(var sLine: string; const sKey: string): string;
    var
       i : Int32;
    begin
       i := Pos(sKey + ' ', sLine);                  // ex. sLine = 'abc def ghi', sKey = 'def' => i = 5
       if i = 0 then begin                           // ex.             i^  ^i+Length(sKey)
          Result := sLine;
          sLine  := '';
       end
       else begin
          Result := TrimRight(Copy(sLine, 1, i-1));          // ex. Result = 'abc'   ('abc ' - ' ')
          sLine  := TrimLeft (Copy(sLine, i+Length(sKey)));  // ex. sLine  = 'ghi'   (' ghi' - ' ')
       end;
    end;
     
    function GetNext(var sLine: string): string; inline;
    begin
       Result := GetKey(sLine, '')
    end;
    Je me suis contenté d'un GetKey et d'un GetNext. Par ailleurs, comme GetKey est amélioré, je suis revenu sur un GetNext qui l'appelle. On perd alors juste un appel de fonction et un Length(sKey) dont on sait qu'il vaut 0;

    Améliorer la lisibilité est effectivement indispensable ne serait-ce que pour comprendre comment ça marche. Mais on marche sur des œufs, car modifier le code pour améliorer la lisibilité se fait avant une compréhension fiable donc fragilise les modifications.

    Salut
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  2. #42
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 158
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 158
    Billets dans le blog
    9
    Par défaut
    Merci pour vos contributions !

    Après vérification, aucun Trim n'est nécessaire dans la function Entnimm.

    j'ai ajouté des lignes dans le fichier feuerstein.log pour bien voir ce que la fonction faisait. Cette fois c'est clair (pour moi).

    Code X : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
        5958 < uci
        5958 DEBUG [Entnimm] S(1) = [uci]
        5958 DEBUG [Entnimm] S(2) = [] Result = [uci]
        5958 > id name Feuerstein 0.4.6.1
    id author Fritz Grau
    option name Hash type spin default 32 min 1 max 512
    option name 2nd type combo default on var full var on var off
    option name memory type check default true
    option name extend type spin default 2 min 0 max 5
    option name reduce type spin default 2 min 0 max 2
    option name Ponder type check default true
    uciok
       36150 < position startpos
       36150 DEBUG [Entnimm] S(1) = [position startpos]
       36150 DEBUG [Entnimm] S(2) = [startpos] Result = [position]
       42563 < go movetime 1000
       42563 DEBUG [Entnimm] S(1) = [go movetime 1000]
       42563 DEBUG [Entnimm] S(2) = [movetime 1000] Result = [go]
       42564 DEBUG [Entnimm] S(1) = [movetime 1000]
       42564 DEBUG [Entnimm] S(2) = [1000] Result = [movetime]
       42564 DEBUG [Entnimm] S(1) = [1000]
       42564 DEBUG [Entnimm] S(2) = [] Result = [1000]
       42564 > info score cp 8 depth 1 seldepth 1 nodes 1 nps 1 hashfull 0 pv g1h3
       42564 > info score cp 14 depth 1 seldepth 1 nodes 1 nps 1 hashfull 0 pv c2c3
       42564 > info score cp 28 depth 1 seldepth 1 nodes 1 nps 1 hashfull 0 pv b1c3
       42564 > info score cp 37 depth 1 seldepth 1 nodes 1 nps 1 hashfull 0 pv d2d3
       42564 > info score cp 0 depth 2 seldepth 2 nodes 3 nps 3 hashfull 0 pv d2d3 d7d6
       42564 > info score cp 28 depth 3 seldepth 3 nodes 44 nps 44 hashfull 0 pv d2d3 d7d6 b1c3
       42565 > bestmove d2d3 ponder d7d6
       42565 > info string d2d4 d7d5 b1c3 cp 28
       44932 < quit
       44932 DEBUG [Entnimm] S(1) = [quit]
       44932 DEBUG [Entnimm] S(2) = [] Result = [quit]
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  3. #43
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 158
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 158
    Billets dans le blog
    9
    Par défaut
    Et la fonction EntnimmBis (une fois corrigée) n'en a pas besoin non plus (de Trim). Arrêtons de trimer.

    Code X : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
       10915 < position startpos moves e2e4 e7e5
       10915 DEBUG [Entnimm] S(1) = [position startpos moves e2e4 e7e5]
       10915 DEBUG [Entnimm] S(2) = [startpos moves e2e4 e7e5] Result = [position]
       10915 DEBUG [EntnimmBis] S(1) = [startpos moves e2e4 e7e5] Wort = [moves]
       10915 DEBUG [EntnimmBis] S(2) = [e2e4 e7e5] Result = [startpos]
       10915 DEBUG [Entnimm] S(1) = [e2e4 e7e5]
       10915 DEBUG [Entnimm] S(2) = [e7e5] Result = [e2e4]
       10915 DEBUG [Entnimm] S(1) = [e7e5]
       10915 DEBUG [Entnimm] S(2) = [] Result = [e7e5]
       15747 < position fen rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1
       15747 DEBUG [Entnimm] S(1) = [position fen rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1]
       15747 DEBUG [Entnimm] S(2) = [fen rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1] Result = [position]
       15747 DEBUG [EntnimmBis] S(1) = [fen rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1] Wort = [moves]
       15747 DEBUG [EntnimmBis] S(2) = [] Result = [fen rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1]
       15747 DEBUG [Entnimm] S(1) = [fen rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1]
       15747 DEBUG [Entnimm] S(2) = [rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1] Result = [fen]
       17610 < quit
       17610 DEBUG [Entnimm] S(1) = [quit]
       17610 DEBUG [Entnimm] S(2) = [] Result = [quit]
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  4. #44
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 624
    Par défaut
    Bonjour,

    Je pense que la fonction Trim est juste une sécurité pour les éventuels caractères parasites. S'il n'y en a pas elle ne sert à rien. De plus elle traite les caractères d'extrémité, elle ne verra donc pas un caractère parasite qui ne serait ni en extrémité ni près d'un espace séparateur (i.e. dans un mot).

    Pour bien faire, il me semble qu'il faudrait traiter toute la chaîne avant d'en rechercher les tokens : une recopie supprimant les caractères indus et les répétitions d'espaces. Ensuite la recherche pourrait se faire en toute sécurité sans aucun trim.

    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  5. #45
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 158
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 158
    Billets dans le blog
    9
    Par défaut
    @Guesset

    Bonjour. En effet. Cela dit, dans des conditions normales d'utilisation, il n'y aura jamais de commande mal formée, donc je crois qu'on peut se passer du contrôle en question.
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  6. #46
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 158
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 158
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par Guesset Voir le message
    Je pense qu'il faudrait utiliser -1 et 0 :
    Il m'a fallu relire deux ou trois fois ton message (et écrire un petit programme) pour bien comprendre. Maintenant je vois :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    {$ASSERTIONS ON}
     
    uses
      StrUtils;
     
    var
      i: integer;
     
    begin
      i := 5;
      Assert(IntToBin(i, 4) = '0101');
      i *= -1;
      Assert(IntToBin(i, 4) = '1011');
     
      i := 0 xor 0;
      Assert(IntToBin(i, 4) = '0000');
      i := 0 xor -1;
      Assert(IntToBin(i, 4) = '1111');
      i := -1 xor -1;
      Assert(IntToBin(i, 4) = '0000');
     
      i := 5 + 0 and 8;
      Assert(IntToBin(i, 4) = '0101');
      i := 5 + -1 and 8;
      Assert(IntToBin(i, 4) = '1101');
    end.
    Citation Envoyé par Guesset Voir le message
    Mais avant de le mettre éventuellement en œuvre, il convient de bien regarder l'impact global.
    Justement, il y a des endroits où l'emploi de -1 et 1 se justifie :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        geschlagen := Figur; (* Pièce capturée *)
        if geschlagen <> 0 then
        begin
          Inc(Bewertung, MatWert[Figur] * dran); (* Addition ou soustraction de la valeur matérielle *)
    Je ne me sens pas la capacité (ou le courage) de faire la modification que tu suggères. D'un autre côté, ça veut dire (si je comprends bien) qu'il y aurait des données fausses dans certaines parties du programme.

    Je vois que tu es allé plus loin que moi dans la compréhension du programme. Pourrais-tu expliquer comment il représente l'échiquier ? Pour moi, même ce point-là n'est pas clair.

    J'aurais bien aimé aussi comprendre comment fonctionne l'apprentissage (activable avec l'option -dLernen), puisque d'après les essais que j'ai faits il semble fonctionner (ce qui me fascine).

    P.-S. Pour la représentation de l'échiquier, je vois qu'il utilise 128 cases :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    type
      DBrett = array[0..127] of ShortInt;
    Le D voulant dire double je pense.
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  7. #47
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 624
    Par défaut
    Bonjour,

    Je pense que cela doit être vu comme cela :
    Nom : Chess.png
Affichages : 72
Taille : 101,1 Ko

    Un tableau [0..7, 0..7] d'une structure de 4 octets serait plus pratique. Par ailleurs, la solution utilisée n'est pas très rapide car elle adresse des octets mais surtout elle ne bénéficie pas du calcul d'adresse du CPU très efficient notamment pour les puissances de 2 en demandant de tout faire par l'ALU. En outre c'est assez illisible.

    Les couleurs transitées de -1, +1 à -1, 0 ne posent pas de problème :
    Inc(Bewertung, MatWert[Figur] * dran); (* Addition ou soustraction de la valeur matérielle *)
    devient :
    Bewertung += MatWert[Figur] xor dran - dran; (* -1 : complément à 1 + 1 = neg, 0 : élément neutre de xor et add/sub *)
    L'opération doit être au moins 4 fois plus rapide.

    Je crois qu'il sera difficile de progresser sans re-documenter ce projet.

    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  8. #48
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 158
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 158
    Billets dans le blog
    9
    Par défaut
    @Guesset

    Génial, merci ! Je vais essayer d'écrire un petit programme de démonstration.

    Citation Envoyé par Guesset Voir le message
    Je crois qu'il sera difficile de progresser sans re-documenter ce projet.
    Oui, d'accord. Sous quelle forme ?

    Personnellement j'aime bien PasDoc. Il faudrait déplacer le code dans une ou plusieurs unités : Si je me souviens bien, PasDoc ne permet de documenter que les unités. Mais ce serait une bonne chose, non ?

    Citation Envoyé par Guesset Voir le message
    L'opération doit être au moins 4 fois plus rapide.
    Ça vaudrait vraiment le coup d'essayer alors...

    Question. Que dirais-tu de contribuer directement au projet ? Par exemple en créant un fork du dépôt git (ou sous une autre forme équivalente) ? Pour ma part, je ne serais pas capable, à l'instant, de me lancer dans les modifications que vous avez proposées.
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  9. #49
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 624
    Par défaut
    Bonjour,

    La re-documentation est certes celle du code source mais aussi des synthèses et principes extirpés comme le dessin du double échiquier peut l'illustrer.

    Je suis très loin de pouvoir reprendre ce code car je ne comprends toujours pas comment il fonctionne. Pour l'instant, je fais des modifications cosmétiques en espérant ne pas faire de dégâts. Le but est de, petit à petit, le rendre plus lisible pour en pénétrer les arcanes.

    Je l'ai passé en mode free pascal pour bénéficier des cases sur chaînes de caractères (idéal pour les commandes) et bien sûr, en conséquence, j'ai dù remettre moult ^ car FP est moins souple que Delphi.

    J'ai commencé à reprendre des noms de variables mais, même avec l'usage des traducteurs, je reste souvent très perplexe (zug = train par exemple).

    Salutations.
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  10. #50
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 158
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 158
    Billets dans le blog
    9
    Par défaut
    Dans ce contexte, Zug, c'est le coup, ou éventuellement le trait.
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  11. #51
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 624
    Par défaut
    Bonjour,

    Est-ce que quelqu'un sait si +1 est le blanc ou le noir. Je pensais que le noir était -1 ne serait-ce que pour inverser l'axe des Y quand ils jouent mais je ne suis plus si si sûr.

    Merci

    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  12. #52
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 158
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 158
    Billets dans le blog
    9
    Par défaut
    Bonjour. Dans la procédure Drucke (qui sert à écrire dans le fichier log les valeurs de l'échiquier, à des fins de débogage), on voit que les valeurs supérieures à zéro sont les pièces blanches (qu'on représente par des majuscules).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    procedure Drucke(PL: PLage);
    var
      X, Y, Z: Integer;
      S, St: string;
    begin
      with PL^ do
      begin
        for Y := 7 downto 0 do
        begin
          St := '';
          for X := 0 to 7 do
          begin
            Z := Br[X shl 4 + Y];
            if Z = 0 then
              S := '.'
            else if Z > 0 then
              S := UpCase(englisch[Z])
    P.-S. On le voit aussi dans la procédure FEN qui sert à décoder une chaîne FEN (donc le contraire de l'opération précédente) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    procedure FEN(const Zeile: string);
    { ... }
    begin
      { ... }
            if Zeile[I] >= #96 then { lettre minuscule }
              Farbe := -1 { couleur noire }
            else
              Farbe := 1;
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  13. #53
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 158
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 158
    Billets dans le blog
    9
    Par défaut
    Je viens de faire une (dernière ?) mise à jour de la version avec noms de variables en anglais.

    Je me demande s'il serait raisonnable de passer trop de temps sur ce programme. Je pense passer à autre chose. Je reste toutefois à votre disposition si vous avez encore de l'inspiration...
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  14. #54
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 624
    Par défaut
    Merci Roland,

    Citation Envoyé par Roland Chastain Voir le message
    Bonjour. Dans la procédure Drucke (qui sert à écrire dans le fichier log les valeurs de l'échiquier, à des fins de débogage), on voit que les valeurs supérieures à zéro sont les pièces blanches (qu'on représente par des majuscules).
    Salut
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  15. #55
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 489
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 489
    Par défaut
    Salut.

    Voici comment je verrais l'interpréteur de commande.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
     
    unit UInterpreter;
     
    interface
     
    uses
      SysUtils, Classes, Generics.Collections;
     
    type
      // Signature d'une fonction de d'edition et visualisation
      TonEvtWriteln  = Procedure(StrValues : String) of Object;
      // Types de paramètres
      TParamType = (ptString, ptInteger, ptBoolean, ptMove, ptColor);
     
      // Définition d'un paramètre de commande
      TCommandParam = record
        Name: string;
        ParamType: TParamType;
        Required: Boolean;
        DefaultValue: string;
        Description: string;
      end;
     
      // Signature d'une fonction de commande
      TCommandHandler = function(const Params: TArray<string>): Boolean of object;
     
      // Définition d'une commande
      TCommandDef = record
        Name: string;
        Handler: TCommandHandler;
        Parameters: TArray<TCommandParam>;
        Description: string;
        Aliases: TArray<string>;
      end;
     
      // Classe principale de l'interpréteur
      TCommandInterpreter = class
      private
        FCommands: TDictionary<string, TCommandDef>;
        FCurrentCommand: string;
        FDebugMode: Boolean;
        FonWriteln : TonEvtWriteln;
     
        function ParseCommand(const Input: string): TArray<string>;
        function ValidateParameters(const Command: TCommandDef; const Params: TArray<string>): Boolean;
        function GetCommandHelp(const CommandName: string): string;
        procedure LogError(const ErrorMsg: string);
        procedure LogDebug(const DebugMsg: string);
    	Procedure _WriteLn(StrValues : String);
     
      public
        constructor Create;
        destructor Destroy; override;
     
        // Enregistrement des commandes
        procedure RegisterCommand(const Name: string; Handler: TCommandHandler; 
                                 const Params: TArray<TCommandParam>; 
                                 const Description: string = '';
                                 const Aliases: TArray<string> = nil);
     
        // Exécution des commandes
        function ExecuteCommand(const Input: string): Boolean;
        function ExecuteCommandLine(const CommandLine: string): Boolean;
     
        // Utilitaires
        function IsValidCommand(const CommandName: string): Boolean;
        function GetCommandList: TArray<string>;
        function GetHelp(const CommandName: string = ''): string;
     
        property DebugMode: Boolean read FDebugMode write FDebugMode;
    	property OnWriteLn : TonEvtWriteln read FonWriteln write FonWriteln;
      end;
    Implementation 
     
    { TCommandInterpreter }
     
    constructor TCommandInterpreter.Create;
    begin
      inherited Create;
      FCommands := TDictionary<string, TCommandDef>.Create;
      FDebugMode := False;
    end;
     
    destructor TCommandInterpreter.Destroy;
    begin
      FCommands.Free;
      inherited Destroy;
    end;
     
    procedure TCommandInterpreter.RegisterCommand(const Name: string; 
      Handler: TCommandHandler; const Params: TArray<TCommandParam>; 
      const Description: string; const Aliases: TArray<string>);
    var
      CommandDef: TCommandDef;
      Alias: string;
    begin
      CommandDef.Name := LowerCase(Name);
      CommandDef.Handler := Handler;
      CommandDef.Parameters := Params;
      CommandDef.Description := Description;
      CommandDef.Aliases := Aliases;
     
      // Enregistrer la commande principale
      FCommands.AddOrSetValue(CommandDef.Name, CommandDef);
     
      // Enregistrer les aliases
      for Alias in Aliases do
        FCommands.AddOrSetValue(LowerCase(Alias), CommandDef);
    end;
     
    function TCommandInterpreter.ParseCommand(const Input: string): TArray<string>;
    var
      Parts: TStringList;
      i: Integer;
    begin
      Parts := TStringList.Create;
      try
        Parts.Delimiter := ' ';
        Parts.DelimitedText := Trim(Input);
     
        SetLength(Result, Parts.Count);
        for i := 0 to Parts.Count - 1 do
          Result[i] := Parts[i];
      finally
        Parts.Free;
      end;
    end;
     
    function TCommandInterpreter.ValidateParameters(const Command: TCommandDef; 
      const Params: TArray<string>): Boolean;
    var
      i, RequiredCount: Integer;
      Param: TCommandParam;
    begin
      Result := True;
      RequiredCount := 0;
     
      // Compter les paramètres requis
      for Param in Command.Parameters do
        if Param.Required then
          Inc(RequiredCount);
     
      // Vérifier le nombre minimum de paramètres
      if Length(Params) - 1 < RequiredCount then // -1 car le premier élément est le nom de la commande
      begin
        LogError(Format('Commande "%s": %d paramètres requis, %d fournis', 
                       [Command.Name, RequiredCount, Length(Params) - 1]));
        Result := False;
      end;
     
      // Vérifier le nombre maximum de paramètres
      if Length(Params) - 1 > Length(Command.Parameters) then
      begin
        LogError(Format('Commande "%s": trop de paramètres (%d max, %d fournis)', 
                       [Command.Name, Length(Command.Parameters), Length(Params) - 1]));
        Result := False;
      end;
    end;
     
    function TCommandInterpreter.ExecuteCommand(const Input: string): Boolean;
    var
      Params: TArray<string>;
      CommandDef: TCommandDef;
      CommandName: string;
    begin
      Result := False;
     
      if Trim(Input) = '' then
        Exit;
     
      try
        Params := ParseCommand(Input);
        if Length(Params) = 0 then
          Exit;
     
        CommandName := LowerCase(Params[0]);
        FCurrentCommand := CommandName;
     
        if not FCommands.TryGetValue(CommandName, CommandDef) then
        begin
          LogError(Format('Commande inconnue: "%s"', [CommandName]));
          Exit;
        end;
     
        if not ValidateParameters(CommandDef, Params) then
          Exit;
     
        LogDebug(Format('Exécution de la commande: %s', [Input]));
        Result := CommandDef.Handler(Params);
     
      except
        on E: Exception do
        begin
          LogError(Format('Erreur lors de l''exécution de "%s": %s', [Input, E.Message]));
          Result := False;
        end;
      end;
    end;
     
    function TCommandInterpreter.ExecuteCommandLine(const CommandLine: string): Boolean;
    var
      Commands: TStringList;
      i: Integer;
    begin
      Result := True;
      Commands := TStringList.Create;
      try
        Commands.Delimiter := ';';
        Commands.DelimitedText := CommandLine;
     
        for i := 0 to Commands.Count - 1 do
        begin
          if not ExecuteCommand(Trim(Commands[i])) then
          begin
            Result := False;
            Break;
          end;
        end;
      finally
        Commands.Free;
      end;
    end;
     
    function TCommandInterpreter.IsValidCommand(const CommandName: string): Boolean;
    begin
      Result := FCommands.ContainsKey(LowerCase(CommandName));
    end;
     
    function TCommandInterpreter.GetCommandList: TArray<string>;
    var
      CommandName: string;
      UniqueCommands: TStringList;
    begin
      UniqueCommands := TStringList.Create;
      try
        UniqueCommands.Sorted := True;
        UniqueCommands.Duplicates := dupIgnore;
     
        for CommandName in FCommands.Keys do
          UniqueCommands.Add(CommandName);
     
        Result := UniqueCommands.ToStringArray;
      finally
        UniqueCommands.Free;
      end;
    end;
     
    function TCommandInterpreter.GetHelp(const CommandName: string): string;
    var
      CommandDef: TCommandDef;
      Param: TCommandParam;
    begin
      if CommandName = '' then
      begin
        Result := 'Commandes disponibles:' + sLineBreak;
        for CommandDef in FCommands.Values do
          Result := Result + Format('  %s - %s' + sLineBreak, [CommandDef.Name, CommandDef.Description]);
      end
      else
      begin
        if FCommands.TryGetValue(LowerCase(CommandName), CommandDef) then
        begin
          Result := Format('Commande: %s' + sLineBreak, [CommandDef.Name]);
          Result := Result + Format('Description: %s' + sLineBreak, [CommandDef.Description]);
     
          if Length(CommandDef.Parameters) > 0 then
          begin
            Result := Result + 'Paramètres:' + sLineBreak;
            for Param in CommandDef.Parameters do
            begin
              Result := Result + Format('  %s (%s)%s - %s' + sLineBreak, 
                                       [Param.Name, 
                                        GetEnumName(TypeInfo(TParamType), Ord(Param.ParamType)),
                                        IfThen(Param.Required, ' [requis]', ' [optionnel]'),
                                        Param.Description]);
            end;
          end;
        end
        else
          Result := Format('Commande inconnue: %s', [CommandName]);
      end;
    end;
     
    procedure TCommandInterpreter.LogError(const ErrorMsg: string);
    begin
      _WriteLn('ERREUR: ' + ErrorMsg);
    end;
     
    procedure TCommandInterpreter.LogDebug(const DebugMsg: string);
    begin
      if FDebugMode then
        _WriteLn('DEBUG: ' + DebugMsg);
    end;
    Procedure _WriteLn(StrValue : String) ;
    Begin 
      If Assigned(FonWriteln) Then 
        FonWriteln(StrValue);
    End;
     
    End;
    Ensuite il n'y reste plus qu'à implémenter le moteur. Par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    Unit UChessEngine;
    Implementation 
     uses UInterpreteur
    // Exemple d'implémentation pour un moteur d'échecs
    type
      TonEvtWrite  = Procedure(StrValues : String) of Object;
     
      TChessEngine = class
      private
        FInterpreter: TCommandInterpreter;
        FPosition: string;
        FThinking: Boolean;
        FOnWriteLn : TonEvtWriteln;
    	FOnWrite   : TonEvtWrite  ;
     
        // Handlers des commandes
        function HandleUCI(const Params: TArray<string>): Boolean;
        function HandleIsReady(const Params: TArray<string>): Boolean;
        function HandlePosition(const Params: TArray<string>): Boolean;
        function HandleGo(const Params: TArray<string>): Boolean;
        function HandleStop(const Params: TArray<string>): Boolean;
        function HandleQuit(const Params: TArray<string>): Boolean;
        function HandleSetOption(const Params: TArray<string>): Boolean;
        function HandleDebug(const Params: TArray<string>): Boolean;
     
    	Procedure _WriteLn(StrValues : String);
    	Procedure _Write(StrValues : String);
      public
        constructor Create;
        destructor Destroy; override;
     
        procedure InitializeCommands;
        Function ProcessInput(const Input: string) : String;
        procedure MainLoop;
        property OnWriteLn : TonEvtWriteln read FonWriteln write FonWriteln;
    	property OnWrite   : TonEvtWrite read FonWrite write FonWrite;
      end;
     
    implementation
     
    { TChessEngine }
     
    constructor TChessEngine.Create;
    begin
      inherited Create;
      FInterpreter := TCommandInterpreter.Create;
      OnWriteLn := FInterpreter.OnWriteLn;
      FPosition := 'startpos';
      FThinking := False;
      InitializeCommands;
    end;
     
    destructor TChessEngine.Destroy;
    begin
      FInterpreter.Free;
      inherited Destroy;
    end;
     
    procedure TChessEngine.InitializeCommands;
    begin
      // Commandes UCI standard
      FInterpreter.RegisterCommand('uci', HandleUCI, [], 
        'Initialise le protocole UCI');
     
      FInterpreter.RegisterCommand('isready', HandleIsReady, [], 
        'Vérifie si le moteur est prêt');
     
      FInterpreter.RegisterCommand('position', HandlePosition, [
        TCommandParam.Create('type', ptString, True, '', 'startpos ou fen'),
        TCommandParam.Create('moves', ptString, False, '', 'liste des coups')
      ], 'Définit la position');
     
      FInterpreter.RegisterCommand('go', HandleGo, [
        TCommandParam.Create('depth', ptInteger, False, '0', 'profondeur de recherche'),
        TCommandParam.Create('time', ptInteger, False, '0', 'temps en millisecondes')
      ], 'Lance la recherche');
     
      FInterpreter.RegisterCommand('stop', HandleStop, [], 
        'Arrête la recherche');
     
      FInterpreter.RegisterCommand('quit', HandleQuit, [], 
        'Quitte le programme', ['exit', 'q']);
     
      FInterpreter.RegisterCommand('setoption', HandleSetOption, [
        TCommandParam.Create('name', ptString, True, '', 'nom de l\'option'),
        TCommandParam.Create('value', ptString, True, '', 'valeur de l\'option')
      ], 'Définit une option');
     
      FInterpreter.RegisterCommand('debug', HandleDebug, [
        TCommandParam.Create('mode', ptBoolean, False, 'false', 'active/désactive le debug')
      ], 'Mode debug');
    end;
     
    function TChessEngine.HandleUCI(const Params: TArray<string>): Boolean;
    begin
      _WriteLn('id name MonMoteur 1.0');
      _WriteLn('id author VotreNom');
      _WriteLn('uciok');
      Result := True;
    end;
     
    function TChessEngine.HandleIsReady(const Params: TArray<string>): Boolean;
    begin
      _WriteLn('readyok');
      Result := True;
    end;
     
    function TChessEngine.HandlePosition(const Params: TArray<string>): Boolean;
    begin
      if Length(Params) > 1 then
      begin
        FPosition := Params[1];
        _WriteLn('Position définie: ' + FPosition);
      end;
      Result := True;
    end;
     
    function TChessEngine.HandleGo(const Params: TArray<string>): Boolean;
    begin
      FThinking := True;
      _WriteLn('Recherche en cours...');
      // Ici tu lanceras votre algorithme de recherche
      _WriteLn('bestmove e2e4');
      FThinking := False;
      Result := True;
    end;
     
    function TChessEngine.HandleStop(const Params: TArray<string>): Boolean;
    begin
      if FThinking then
      begin
        FThinking := False;
        _WriteLn('Recherche interrompue');
      end;
      Result := True;
    end;
     
    function TChessEngine.HandleQuit(const Params: TArray<string>): Boolean;
    begin
      _WriteLn('Au revoir!');
      Result := False; // Indique qu'il faut arrêter la boucle principale
    end;
     
    function TChessEngine.HandleSetOption(const Params: TArray<string>): Boolean;
    begin
      if Length(Params) >= 3 then
        _WriteLn(Format('Option %s définie à %s', [Params[1], Params[2]]));
      Result := True;
    end;
     
    function TChessEngine.HandleDebug(const Params: TArray<string>): Boolean;
    begin
      if Length(Params) > 1 then
        FInterpreter.DebugMode := LowerCase(Params[1]) = 'true';
      _WriteLn('Mode debug: ' + BoolToStr(FInterpreter.DebugMode, True));
      Result := True;
    end;
     
    Function TChessEngine.ProcessInput(const Input: string) : Boolean;
    begin
      Result := FInterpreter.ExecuteCommand(Input);
    end;
     
    procedure TChessEngine.MainLoop;
    var
      Input: string;
      Continue: Boolean;
    begin
      Continue := True;
      _WriteLn('Moteur d''échecs - Tapez "help" pour l''aide');
     
      while Continue do
      begin
        _Write('> ');
        ReadLn(Input);
     
        if LowerCase(Trim(Input)) = 'help' then
          _WriteLn(FInterpreter.GetHelp)
        else
          Continue := ProcessInput(Input);
      end;
    end;
     
    Procedure TChessEngine._WriteLn(StrValue : String) ;
    Begin 
      If Assigned(FonWriteln) Then 
        FonWriteln(StrValue);
    End;
     
    end.
    Je pense que cela serait un plus pour la maintenance du code source et cela permettra de nous concentrer sur l'essentiel plutôt que d'essayer de comprendre ses choix.

    PS : Le code est en Delphi mais je pense que ce n'est pas insurmontable de le passer en Pascal.
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag :resolu:

  16. #56
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 158
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 158
    Billets dans le blog
    9
    Par défaut
    @anapurna

    Merci pour l'exemple. Je vais l'étudier.
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo