2010-02-05 11 views
8

Je suis en train de jouer avec une aventure MUD/texte (s'il vous plaît ne riez pas) dans Ruby. Quelqu'un peut-il me donner des indications sur une solution élégante, basée sur l'OOP, pour analyser le texte d'entrée?Elégant commande-analyse dans un jeu de texte basé sur la POO

Nous ne parlons ici de rien de plus complexe que "mettre la baguette sur la table". Mais tout doit être doux. Je veux étendre l'ensemble de commandes sans douleur, plus tard.

Mes pensées actuelles, légèrement simplifié:

  1. Chaque classe d'élément (boîte, table, salle, lecteur) sait reconnaître une commande qui « appartient » à elle.

  2. La classe de jeu comprend une sorte d'un domaine spécifique langage impliquant des actions telles que « objet mouvement X à l'intérieur de l'objet Y », « Description de l'exposition de l'objet X », etc.

  3. La classe de jeu demande à chaque élément dans la pièce s'il reconnaît la commande d'entrée. Premier à dire oui gagne.

  4. Ensuite, il transmet le contrôle à une méthode de la classe d'éléments qui gère la commande. Cette méthode reformule la commande dans le DSL, la renvoie à l'objet du jeu pour que cela se produise.

Il doit y avoir des façons élégantes et usitées de faire ce genre de choses. Je n'arrive pas à google quoi que ce soit, cependant.

+0

En note de bas de page, le bit velu avec mon plan actuel met en œuvre des actions qui impliquent deux objets. – Shadowfirebird

+1

Vous pouvez commencer par http://stackoverflow.com/questions/tagged/natural-language et voir où cela mène. – dmckee

+0

Ta! Je viens d'ajouter cette balise à la question. – Shadowfirebird

Répondre

3

Le Interpreter design pattern est l'approche orientée objet la plus orientée à l'analyse que je connais, mais je suis sûr que les experts du compilateur souligneront les algorithmes qui sont plus puissants.

+0

Je suis des déchets à des motifs de conception, et mon googling avait échoué à voir celui-ci. Je vais certainement y jeter un coup d'oeil, ta. – Shadowfirebird

+0

En effet, le motif interpréteur ressemble à un arbre d'expression dans un processus de compilation! agréable. Cela semble être une implémentation directe pour un compilateur. (après l'analyse du jeton de chaîne) –

+0

J'ai toujours du mal à appliquer ce modèle à mon projet, mais cela ressemble plutôt à l'idée que je cherchais à tâtonner. Ce qu'il ne dit pas, cependant, est comment la chaîne de commande est analysée. – Shadowfirebird

0

diviser en jetons que le format sera toujours:
[commande] [object1] ([référent] [object2])

Vous pouvez appeler la méthode [commande] sur [object1] dans votre chambre et passez-le [object2] s'il y a lieu.

+0

C'est tellement tentant. Mais, "allume la lumière". Ou, d'ailleurs, ce serait vraiment bien d'accepter "allumer la lumière". – Shadowfirebird

+1

Vous pourriez le faire en supprimant simplement ce qui est habituellement appelé "mots d'arrêt" de la chaîne. Des mots comme "le", "un", "sur". Dans ce cas, tout ce qui reste de la phrase "allumer cette lumière là" serait "allumer la lumière". Bien sûr, cela peut être beaucoup trop, mais dans ce cas précis, l'absence du mot «off» vous dit tout ce que vous devez savoir. –

+0

@Jorg: En fait, c'est à peu près ce que fait mon approche actuelle, sauf qu'elle détecte des "mots de départ" à la place. Donc (pour simplifier quelque peu) la classe light cherche /light.*(on|off)/. Peut-être que vous avez le bon chemin, et je ne le fais pas, cependant. – Shadowfirebird

1

Pour les interpréteurs de commandes, je suis plutôt friand de ce simple, pas tout ce motif élégant. Les modèles dans les langages dynamiques ont tendance à impliquer moins de boîtes et de lignes que les modèles GOF.

class Thing 

    # Handle a command by calling the method "cmd_" + command. 
    # Raise BadCommand exception if there is no method for that command. 

    def handle_command(command, args) 
    method_name = "cmd_#{command}" 
    raise BadCommand, command unless respond_to?(method_name) 
    send(method_name, args) 
    end 

    def cmd_quit(args) 
    # the code for command "quit" 
    end 

    def cmd_list(args) 
    # the code for command "list" 
    end 

    ... 

end 

De cette manière, l'ajout d'une nouvelle commande consiste simplement à ajouter une nouvelle méthode. Aucune table ou instruction de cas ne doit être ajustée.

+2

Cela ressemble au premier strabisme comme un tridimensionnel à trois voies entre Visiteur, Stratégie et Commandement, mais comme vous l'avez dit: dans un langage expressif (je n'achète pas la partie "dynamique" * beaucoup *, il serait probablement aussi élégant à Scala, F # ou Haskell) ce n'est pas si grave. Rappelez-vous: un Pattern n'est rien d'autre qu'un programme que vous souhaitez écrire, mais votre langage ne vous le permet pas. Eh bien, Ruby * vous le permet. –

+0

@Jorg, Bien dit. Je creuse cette définition d'un motif. Est-ce le vôtre? –

+3

Je ne pense pas. Cette formulation * précise pourrait être la mienne, mais l'idée est générale. En fait, si vous retournez votre copie du GoF à la page 4 et que vous lisez le dernier paragraphe de la section 1.1, c'est écrit là. La diatribe classique sur ceci est http://blog.plover.com/prog/design-patterns.html avec cette réponse http://www.cincomsmalltalk.com/userblogs/ralph/blogView?entry=3335803396 et alors ce http: //blog.plover.com/prog/johnson.html. Et bien sûr la fameuse présentation Norvig: http://norvig.com/design-patterns/ –

0

Ok. Donc vous avez besoin d'une sémantique? (tour est une action, allume un objet, sur un argument ... (je me rapporte à votre commentaire à dbemerlin)). Pourquoi ne pas définir une grammaire? humm ... Je suppose que lex et yacc ne sont pas une option? (puisque ce n'est pas du tout la POO, mais ce que vous voulez faire est de "compiler" l'entrée de l'utilisateur pour produire quelque chose - exécuter du code qui change les données de la pièce et produire un résultat)

Vous pouvez avoir une POO conception pour votre objet et son action (comme, tous les objets ont une méthode .describeMe() ..), et à côté de cela, un analyseur d'entrée + compilateur.

Est-ce que je suis complètement hors sujet?Edit: après avoir regardé le modèle d'interprète mis en évidence par Marc Seeman, il semble que ce soit la façon d'y aller, vous le voulez dans OOP. (mais vous allez quelque peu réinventer la roue)

+0

J'ai regardé lex et yacc. Mais ils me font mal à la tête, et c'est censé être un projet amusant.De plus, si je comprends bien, ils me lient à une grammaire beaucoup plus stricte que la langue anglaise a réellement. Je suppose que ma cible en or est pour l'utilisateur d'être capable de taper "sur la table mettre la baguette" un être compris ... ou au moins avoir le jeu essayer de mettre la table sur la baguette;) – Shadowfirebird

2

On dirait que vous avez besoin d'un analyseur.

Divisez la chaîne d'entrée en jetons (mots). Ensuite, alimentez les jetons, un à la fois, sur une machine d'état. Je trouve que l'automate push-down est plutôt intuitif et puissant pour écrire un tel style.

+0

Toutes les suggestions sur la façon dont Je commence à étudier le concept de machines d'état? L'entrée de Wikipedia est une donnée, bien sûr. – Shadowfirebird

+1

Je reprends le commentaire wikipedia. La page sur les automates à pile est fascinante, mais elle est écrite en mathématiques avancées. – Shadowfirebird

+1

@Shadow: http://stackoverflow.com/questions/1669/learning-to-write-a-compiler est la page canonique pour les ressources du compilateur sur SO. Mais vous avez besoin est spécialisé et peut ne pas être bien traité. Cette réponse est techniquement correcte, mais pas très utile parce que le traitement du langage naturel est notoirement difficile et a sa propre culture et sa propre langue. – dmckee