[Algo] Parseur de commandes "interlligent"

Parseur de commandes "interlligent" [Algo] - Algo - Programmation

Marsh Posté le 18-07-2004 à 18:08:19    

Imaginons que j'ai une série de commandes :
 
gossip
say
tell
north
south
east
west
up
down
sleep
wake
...
 
certaines prennent des arguments (gossip [text], tell [character] [text], etc.)
 
Je récupère du texte saisi par l'utilisateur mettons à l'aide un Console.Readline()
 
Je voudrais déjà savoir comment faire un parseur de commandes afin de reconnaître la commande qu'il tente d'utiliser. Je peux évidement tester chacun de ces mots et vérifier qu'ils sont en début de chaîne... Mais cela ne me semble pas terrible comme solution, saurtout parceque je veux aussi autrechose...
 
En effet, je veux que si l'utilisateur ne saisi que le début d'une commande, à condition qu'il soit sufiisament discriminent, éxécuter la fonction correspondante.
 
Par exemple :
 
go Salut !
doit revenir au même que
gossip Salut !
 
sl reviennent à sleep
 
Par contre (bah ouais, sinon c'est trop simple) je veux que pour "south", il suffise de taper "s", même si c'est aussi assimilable à "sleep".
 
Y'a un autre moyen que de tester comme un goret l'intégralité des choix possibles ?

Reply

Marsh Posté le 18-07-2004 à 18:08:19   

Reply

Marsh Posté le 18-07-2004 à 20:01:09    

Ca inspire les foules mes problèmes c'est fou !
 
Pour info, j'ai trouvé un compromis :
 

Code :
  1. struct commande
  2. {
  3.  public string cmd;
  4.  public int  nbChar;
  5.  public bool  alone;
  6. }
  7. public class Session
  8. {
  9.  private const int nbCmd = 2;
  10.  private commande[] commandes = new commande[nbCmd];
  11.  Session
  12.  {
  13.   commandes[0].cmd = "gossip";
  14.   commandes[0].nbChar = 1;
  15.   commandes[0].alone = false;
  16.   commandes[1].cmd = "quit";
  17.   commandes[1].nbChar = 4;
  18.   commandes[1].alone = true;
  19.  }
  20.  private bool parseInput(string msg)
  21.  {
  22.   if (!authentified)
  23.   {
  24.    if (msg.IndexOf(" " ) != -1)
  25.    {
  26.     return true;
  27.    }
  28.    for (int i = 0; i < nbCmd; i++)
  29.    {
  30.     if (commandes[i].cmd == msg)
  31.     {
  32.      SendMessage("Invalid name. Please choose another one." );
  33.      msg = "";
  34.      return true;
  35.     }
  36.    }
  37.    EventLog.WriteEntry("MagicMUD", "authentification", EventLogEntryType.Information, 4);
  38.    authentified = player.loadCharacter(msg);
  39.    pool.Broadcast(this.player.CharacterName + " quits real life" );
  40.    SendMessage("Welcome " + player.CharacterName);
  41.   }
  42.   else
  43.   {
  44.    string foundCmd = "";
  45.    int startParams = msg.IndexOf(" " );
  46.                 string currentCmd = (startParams != -1)?msg.Substring(0, startParams):msg;
  47.    for (int i = 0; i < nbCmd; i++)
  48.    {
  49.     if (((startParams == -1) == commandes[i].alone) && (currentCmd.Length <= commandes[i].cmd.Length) && (currentCmd.Length >= commandes[i].nbChar) && (commandes[i].cmd.StartsWith(currentCmd)))
  50.     {
  51.      foundCmd = commandes[i].cmd;
  52.      break;
  53.     }
  54.    }
  55.    switch (foundCmd)
  56.    {
  57.     case "quit":
  58.      SendMessage("\nGood Bye" );
  59.      return false;
  60.      break;
  61.     case "gossip":
  62.      pool.Gossip(player, msg.Substring(startParams));
  63.      break;
  64.     default:
  65.      SendMessage("Hum?" );
  66.      break;
  67.    }
  68.   }
  69.   return true;
  70.  }
  71. }


 
 
Et ça marche :
 


Enter your name: MagicBuzz
MagicBuzz quits real life
 
Welcome MagicBuzz
 
g
Hum?
 
go
Hum?
 
gos
Hum?
 
gossi
Hum?
 
gossip
Hum?
 
gossipe
Hum?
 
g :)
MagicBuzz gossips  :)
 
go :)
MagicBuzz gossips  :)
 
gos :)
MagicBuzz gossips  :)
 
goss :)
MagicBuzz gossips  :)
 
gossi :)
MagicBuzz gossips  :)
 
gossip :)
MagicBuzz gossips  :)
 
gossipe :)
Hum?
 
q
Hum?
 
qui
Hum?
 
qu
Hum?
 
quit world
Hum?
 
a world
Hum?
 
q world
Hum?
 
quit
 
Good Bye
 
 
 
Perte de la connexion à l'hôte.
 
H:\Documents and Settings\MagicBuzz>


Message édité par Arjuna le 18-07-2004 à 20:04:16
Reply

Marsh Posté le 18-07-2004 à 20:02:32    

Explication de la struc :
 
cmd : nom de la commande "réelle"
nbChar : nombre de caractères jugés discriminants (il au au moins ce nombre de caractères pour que la commande fonctionne)
alone : flag qui indique si la commande attends de paramètres ou non

Reply

Marsh Posté le 18-07-2004 à 20:04:46    

moi j'adore le module cmd de python

Reply

Marsh Posté le 18-07-2004 à 20:14:21    

qui est basé sur l'instrospection.
 
tu crées eux méthodes par commande : do_<command> et help_<command>. la première accepte une chaine (la ligne entrée) et est appelée dès que le <command> match avec le début de l'entrée

Reply

Marsh Posté le 18-07-2004 à 20:23:30    

vi mais moi je suis en C# :p
 
Et Python fait mon truc ?

Reply

Marsh Posté le 18-07-2004 à 20:31:38    

je m'en fiche. je te dis juste que j'adopterais la même technique que le module cmd standard de python. et je laisserais le parsing des arguments en charge à chaque méthode. donc y a besoin de rien, juste matcher le début et passer la main. tu en fais beaucoup trop à mon gout. t'as un langage avec introspection, jète un oeil, reste pas dans des approches statiques à la C getopt

Reply

Marsh Posté le 18-07-2004 à 20:39:56    

euh... tu peux m'en dire plus sur l'introspection ?
 
Je sais à peine ce que ça veut dire en français, alors en informatique... Y'a pas de ça en ASP, alors je connais pas :D

Reply

Marsh Posté le 18-07-2004 à 20:43:13    

En fait, je vois vaguement ce que tu veux que je fasses, mais bon... Je vais devoir faire autant de tests dans chaque fonction do_<commande>, donc risquer d'en oublier non ?
 
Sinon, le switch pourraît être viré avec une technique à la "eval" de JavaScript (je sais pas si y'a un truc du genre en C#, j'espère pas), mais c'est tellement porc que je préfère à la rigeur un switch de 20 km...

Reply

Marsh Posté le 18-07-2004 à 20:47:07    

moi je te parle d'instrospection :o
 
et le switch est loin d'être rigoureux, c'est con ce que tu dis

Reply

Marsh Posté le 18-07-2004 à 20:47:07   

Reply

Marsh Posté le 18-07-2004 à 20:56:17    

oui et moi je t'ai demandé ce que c'était :o

Reply

Marsh Posté le 18-07-2004 à 20:57:30    

et le switch n'est pas rigoureux, mais mon système permet tout de même de filtrer notamment les problèmes de paramètres absents/inattendus sans devoir réécrire le code à chaque fois.
 
Mais je ne demande qu'à en savoir plus sur l'introspection...

Reply

Marsh Posté le 18-07-2004 à 21:18:14    

bah en (très) gros, quand tu rajoute une commande, elle va se mettre dans un arbre qui est parsé à chaque fois que tu lance une commande.
 
Example:
 
Arbre de départ: NULL
Ajout de la commande "go". L'arbre devient  

Code :
  1. NULL -> go (appel fonction "go" )


Ajout de la commande "gossip". L'arbre devient

Code :
  1. NULL -> go -> NULL (appel fonction "go" )
  2.            -> ssip (appel fonction "gossip" )

Reply

Marsh Posté le 18-07-2004 à 22:21:54    

mais non. tu cherches les méthodes avec un nom qui commence par go, tu les tries.
 
pour chaque entrée, tu trouves celle qui va bien et tu l'appelles.

Reply

Marsh Posté le 18-07-2004 à 23:31:24    

Hmmm... Je crois que j'ai pas tout saisi (l'algo me semble obscure :D)
 
Concrètement, ça donne quoi ? (soit un ti n'exemple de quelques lignes, soit un article/tuto sur le comment ça marche, parceque je vois pas comment c'est censé fonctionner :D)

Reply

Marsh Posté le 18-07-2004 à 23:32:18    

PS: j'ai cherché dans google, mais je n'ai rien trouvé d'intéressant :/

Reply

Marsh Posté le 18-07-2004 à 23:48:34    

Code :
  1. this.commands = this.GetType().FindMembers(MemberTypes.Method,
  2.                                                BindingFlags.Public ,
  3.                                                Type.FilterName, "do_*"
  4.                                                );


 
j'ai rien testé mais ça doit ressembler à un truc comme ça, voir la documentation

Reply

Marsh Posté le 19-07-2004 à 00:37:06    

arjuna >> la méthode que je t'ai donné, c'est une version simplifiée du fonctionnement de Mumps, un vieux langage interprèté dont l'une des spécialité est la gestion des commandes de façon discriminante, sauf qu'ils ont poussés la logique beaucoup plus loin.

Reply

Marsh Posté le 19-07-2004 à 01:29:08    

Groumpf.
Taz > Juste deux petites questions :
- Cette ligne, c'est au moment de la décision de la commande à éxécuter, c'est ça ?
- this.commands correspond à quoi ? Pour le reste de la ligne, je pense avoir une idée de ce que ça peut faire, mais je reste bouche bée si c'est ce que je pense :)

Reply

Marsh Posté le 19-07-2004 à 07:39:05    

non. au démarrage de ton interpréteur, tu analyses this pour récupérer la liste des méthodes qui vont bien. il te faut les méthodes d'instances qui commencent par do_, retourne un int et accepte une chaine en paramètre. tu filtres, tu stockes, tu constitues ton .this.commands. après, à chaque entrée, tu choisis d'appeler qui il faut.
 
Fait une classe Command, après tous interpréteur la dérives et ne font qu'ajouter des do_*

Reply

Marsh Posté le 19-07-2004 à 07:45:00    

OK, vais essayer ça ce soir.
 
Tu connais pas un site où on parlde de ça ?
Parceque sinon je sens que je vais te saouler avec toutes mes questions pendant toute la nuit :D

Reply

Marsh Posté le 19-07-2004 à 07:48:39    

non. Juste la documentation de System.Reflection. Entraine toi déjà à parcourir les méthodes d'une classe

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed