Elegant command-parsing in an OOP-based text game

2019-03-19 20:56发布

I'm playing with writing a MUD/text adventure (please don't laugh) in Ruby. Can anyone give me any pointers towards an elegant, oop-based solution to parsing input text?

We're talking about nothing more complex than "put wand on table", here. But everything needs to be soft; I want to extend the command set painlessly, later.

My current thoughts, slightly simplified:

  1. Each item class (box, table, room, player) knows how to recognise a command that 'belongs' to it.

  2. The game class understands a sort of a domain-specific language involving actions such as "move object X inside object Y", "show description of object X", etc.

  3. The game class asks each item in the room if it recognises the input command. First to say yes wins.

  4. It then passes control to a method in the item class that handles the command. This method rephrases the command in the DSL, passes it back to the game object to make it happen.

There must be well-worn, elegant ways of doing this stuff. Can't seem to google anything, though.

5条回答
ゆ 、 Hurt°
2楼-- · 2019-03-19 21:11

Ok. So you need a semantic ? (turn is an action, light an object, on an argument... (I relate to your comment to dbemerlin)).

Why not defining a grammar ? humm... I guess lex and yacc are not a option ? (since it's not OOP at all, but what you want to do is to "compile" user input to produce something - executing some code who change the data of the room, and output a result)

You can have an OOP design for your object and its action (like, all objects have a .describeMe() method ..) , and beside that, an input parser+compiler.

Am I completely off the subject?

Edit : after looking to the interpreter pattern pointed out by Marc Seeman, it seems to be the way to go in you want it in OOP. (but you will somewhat re-invent the wheel)

查看更多
The star\"
3楼-- · 2019-03-19 21:13

For command interpreters, I'm rather fond of this simple, not all that elegant pattern. Patterns in dynamic languages tend to involve fewer boxes and lines than GOF patterns.

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

In this way, adding a new command is just adding a new method. No tables or case statements need to be adjusted.

查看更多
Bombasti
4楼-- · 2019-03-19 21:18

The Interpreter design pattern is the most object-oriented approach to parsing that I'm aware of, but I'm sure compiler experts will point out algorithms that are more powerful.

查看更多
劳资没心,怎么记你
5楼-- · 2019-03-19 21:22

Sounds like you need a parser.

Split the input string into tokens (words). Then feed the tokens, one at a time, to a state machine. I find that the push-down automata is rather intuitive and powerful way to write such an stm.

查看更多
仙女界的扛把子
6楼-- · 2019-03-19 21:22

Split it into tokens as the format will always be:
[command] [object1] ([refering] [object2])

You could call method [command] on the [object1] in your room and pass it the [object2] if applicable.

查看更多
登录 后发表回答