基于文本的RPG命令解释器

Fal*_*rri 3 interpreter

我只是在玩一个基于文本的RPG,我想知道,命令解释器究竟是如何实现的,现在有更好的方法来实现类似的东西吗?很容易做出大量的if语句,但这似乎很麻烦,特别是考虑到大多数情况pick up the goldpick up gold具有相同效果的相同take gold.我确信这是一个非常深入的问题,我只想知道如何实现这样的解释器的一般概念.或者如果有一个开源游戏,有一个体面和有代表性的翻译,那将是完美的.

答案可以是语言独立的,但要尽量保持合理的东西,而不是prolog或golfscript等.我不确定该标记到底是什么.

Bri*_*ell 6

这种游戏的通常名称是文本冒险或交互式小说(如果是单人游戏),或MUD(如果是多人游戏).

有几种用于编写交互式小说的专用编程语言,例如Inform 6,Inform 7(一种编译为Inform 6的全新语言),TADS,Hugo等.

这是一个Inform 7游戏的例子,它有一个房间,房间里的一个物体,你可以拾取,放下和操纵对象:

"Example Game" by Brian Campbell

The Alley is a room. "You are in a small, dark alley." A bronze key is in the 
Alley. "A bronze key lies on the ground."
Run Code Online (Sandbox Code Playgroud)

播放时产生:

Example Game
An Interactive Fiction by Brian Campbell
Release 1 / Serial number 100823 / Inform 7 build 6E59 (I6/v6.31 lib 6/12N) SD

Alley
You are in a small, dark alley.

A bronze key lies on the ground.

>take key
Taken.

>drop key
Dropped.

>take the key
Taken.

>drop key
Dropped.

>pick up the bronze key
Taken.

>put down the bronze key
Dropped.

>

对于通常比交互式小说引擎更简单的解析器的多人游戏,您可以查看MUD服务器列表.

如果您想编写自己的解析器,可以先从正则表达式中检查输入.例如,在Ruby中(因为您没有指定语言):

case input
  when /(?:take|pick +up)(?: +(?:the|a))? +(.*)/
    take_command(lookup_name($3))
  when /(?:drop|put +down)(?: +(?:the|a))? +(.*)/
    drop_command(lookup_name($3))
end
Run Code Online (Sandbox Code Playgroud)

你可能会发现这会在一段时间后变得很麻烦.您可以使用一些简写来简化它以避免重复:

OPT_ART = "(?: +(?:the|a))?"  # shorthand for an optional article
case input
  when /(?:take|pick +up)#{OPT_ART} +(.*)/
    take_command(lookup_name($3))
  when /(?:drop|put +down)#{OPT_ART} +(.*)/
    drop_command(lookup_name($3))
end
Run Code Online (Sandbox Code Playgroud)

如果你有很多命令,这可能会开始变慢,并且它会依次检查每个命令的输入.您也可能会发现它仍然难以阅读,并且涉及一些难以简单地提取为短序的重复.

那时候,你可能想要研究词法分析器解析器,这个话题对我来说太大了,不能在这里回答.有许多词法分析器和解析器生成器,给出一个语言的描述,将产生一个能够解析该语言的词法分析器或解析器; 查看链接文章的一些起点.

作为解析器生成器如何工作的一个例子,我将在Treetop中给出一个例子,这是一个基于Ruby的解析器生成器:

grammar Adventure
  rule command
    take / drop
  end

  rule take
    ('take' / 'pick' space 'up') article? space object {
      def command
        :take
      end
    }
  end

  rule drop
    ('drop' / 'put' space 'down') article? space object {
      def command
        :drop
      end
    }
  end

  rule space
    ' '+
  end

  rule article
    space ('a' / 'the')
  end

  rule object
    [a-zA-Z0-9 ]+
  end
end
Run Code Online (Sandbox Code Playgroud)

可以使用如下:

require 'treetop'
Treetop.load 'adventure.tt'

parser = AdventureParser.new
tree = parser.parse('take the key')
tree.command            # => :take
tree.object.text_value  # => "key"
Run Code Online (Sandbox Code Playgroud)