我只是在玩一个基于文本的RPG,我想知道,命令解释器究竟是如何实现的,现在有更好的方法来实现类似的东西吗?很容易做出大量的if语句,但这似乎很麻烦,特别是考虑到大多数情况pick up the gold与pick up gold具有相同效果的相同take gold.我确信这是一个非常深入的问题,我只想知道如何实现这样的解释器的一般概念.或者如果有一个开源游戏,有一个体面和有代表性的翻译,那将是完美的.
答案可以是语言独立的,但要尽量保持合理的东西,而不是prolog或golfscript等.我不确定该标记到底是什么.
这种游戏的通常名称是文本冒险或交互式小说(如果是单人游戏),或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)