玩文字冒险游戏是纯粹的乐趣,但乐趣却非常消耗大脑。 但是今天,我们拥有所有这些空闲处理器能力。
如果我们让计算机自己完成游戏,而我们只需要靠在椅子上看,该怎么办? 我们甚至不需要所有这些新奇的神经网络,而只需简单的蛮力。
我们只是将一堆半随机文本放在文本游戏的入口处,然后看看会发生什么。 在信息安全领域,这称为模糊测试。
目标是Z-Machine,这是由Joel Berez和Mark Blanck于1979年开发的虚拟机解释器,Infocom Games的核心。 这是记录模糊事件的理想目标,因为它有据可查,并且具有许多支持工具和库。
Zork在Atari 800XL上发布(塞巴斯蒂安·格伦沃尔德,CC 3.0)迷你Zork
我们将
迷惑的游戏
-MINI-ZORK-1:地下大帝国 。 这是Infokomovsky第一个Zorka的演示版,旨在从盒式磁带而不是软盘引导。 本质上,它是1990年代Commodore的英国用户杂志
Zzap!64的增刊中刊登的广告。
对于那些还没有玩过Zork的人,加载游戏后会看到以下内容:
MINI-ZORK I: The Great Underground Empire Copyright (c) 1988 Infocom, Inc. All rights reserved. ZORK is a registered trademark of Infocom, Inc. Release 34 / Serial number 871124 West of House You are standing in an open field west of a white house, with a boarded front door. You could circle the house to the north or south. There is a small mailbox here. >
提示>邀请用户输入命令OPEN MAILBOX或GO NORTH来前进游戏。 目标是“解决大地下帝国的宝藏并将它们收集在战利品箱中”,以解决难题并降低敌人的数量。
让我们开始寻找动词(和名词)
Zork随附的用户手册给出了可能的命令示例,例如“打开木门”和“术士锁”,“随便滚动滚动然后跟着我”。 但是,用户必须独立猜测如何解决特定的谜语。
诸如GET和DROP(GET / DROP)之类的动词非常明显,标准的8个基点和上/下(UP / DOWN)以及同时进出(IN / OUT)也很明显。 但是用户还必须使用ATTACK,POOL和PRAY,以及发音手册中没有的魔术字。 当游戏没有给玩家足够的线索时,他们嘲笑地称之为“动词搜寻”。
要生成命令,模糊器将需要游戏接受的单词列表及其词汇表。 Z机选择此列表作为游戏词典(它位于每个游戏文件的标准位置)。
(是一种骗局,是的!但是实际上没有其他方法向计算机解释要使用的单词,因为在文本的任何地方都没有提到某些动词。)
生成命令的最简单方法是随机输入一个或多个单词,在我们的例子中是一两个。 我们不知道哪个单词是动词,哪个名词,所以我们生成许多奇怪的命令,例如“ SEE OOPS”和“ DRIVER BELOW”。
显然,这是非常低效的,因为我们必须对N * N个组合(其中N是词汇量)进行排序,才能找到像“杀手”这样的命令。
但是,我们可以作弊一点。 我们将扫描游戏文本输出上的所有单词,并选择在词典中找到的单词。 然后从此列表中选择一个单词(而不是完整的词典)。 例如,如果我们在文本中看到NORTH,WEST,HOUSE和MAILBOX,则更有可能使用这些词。
搜索故事标记
仅给出随机命令,解析器就会发誓,这是胡说八道:
>about painti [ !] >leathe guideb [ "leathe" , .]
(在Z-Machine中,词汇词的长度不得超过6个字符,因此我们会生成“ leathe”之类的词。)
但是,这种such脚将永远持续下去。 我们如何确定哪些道路比其他道路更有希望? 我们将寻找宣传故事的标志。
Z机器具有PRINT指令,可将文本打印到控制台。 这些通常是描述的片段,例如“房屋西侧”和“瓶破了”。 我们将它们每个都注册为标记。
每当我们看到一个新的标记时,我们都会保存当前段落-当前游戏中球队的名单。
我们将此列表与当前标记相关联,因此我们可以(希望)在重播相同的命令后在输出中获得相同的文本。
游戏的每次启动都会选择一个特定的目标标记,并因此选择与之关联的段落。 搜索算法选择旧标记的频率比旧标记高。
我们不会在每个游戏中逐字重播球队,但是我们将添加一些随机球队,并混合顺序。 当我们看到一个新的标记时,我们将增加“成功”参数,该参数的增长将表明可以较少地更改命令列表。 当此参数增长足够时,我们会将其标记为“稳定”,因为我们可以预测到它。
寻找一条捷径
我们进行游戏的方式通常是无效的。 这是用于生成“ Wheeeeeeeeee !!!!!”标记的命令列表:
curse, art, body gate, incant count, the, the egg, repent, from the, the consum, what, leathe, trap- see, breath here, what intnum, about here, leathe guideb, about, about here, pot, here, see, here about, about, self, here about, mangle, see, rug, the, reply, elvish, say, stilet beetle, say toss, pray, gate about, what bolt, guideb, wooden, say knock, say sit, trail and, here, pray leathe, intnum, one, pray one, jump
我们真正需要做的就是输入最后一个命令:JUMP(或DIVE)。 但是搜索算法不知道显示“ Wheeeeeeeeee !!!!!”需要哪个先前的命令。
我们需要减少通过-使它们尽可能短。 当我们看到一个标记时,如果可能的话,我们用较短的命令列表替换相关的段落。 这使我们更快地到达目标标记,从而使我们在达到目标后有更多的动作进行实验。
许多标记(例如“ Wheeeeeeeeee !!!!!”)并不有趣,因为我们可以在游戏开始时一转就实现它们。 通过减少它们的命令列表,我们最终可以确认是这种情况,从而将它们从潜在目标标记的列表中删除。
不只是言语
由于我们可以直接访问Z轴的内部状态,因此可以使用文本输出以外的其他方式来控制搜索。 例如,我们可以确定对象何时从一个房间移到另一个房间,或何时该对象上的其他属性和标志已更改。 将其称为VM标记(虚拟机标记),并与文本标记并行修复它们:
@mv_30_15 (#30) #15 @f_176_10_1 "" (10) ""(#176)
我们需要这样做,因为文本输出无法告诉我们整个故事。 例如,拿起剑或灯,我们将到达相同的标记“ Taken”。VM标记将告知搜索算法何时达到虚拟机的新状态,例如,当玩家移至新房间或拾取或扔掉物体时。
破坏虚拟机
调查游戏状态是一个相当缓慢的过程。 游戏中的首要任务之一是杀死巨魔,这不允许你走得更远。 但是,在此之前,玩家需要在房子里找到一把更高的剑。
为了加快搜索过程,我们将破解Z型机并将游戏状态带到我们之前看到的状态。 例如,我们无意中将剑移到玩家的手中,这使得成功执行“ STAB”命令(刺)成为可能。 (除非添加“ WITH SWORD”,否则“ ATTACK TROLL”将不起作用,但是“ STAB”(刺伤)已经暗示存在锋利的物体,因此可以使用。)
我们只会破解稳定的标记,因此,如果我们能够可靠地重复游戏并且玩家的手变成一把剑,我们将允许破解此状态:“剑在玩家的手中”。 然后,我们可以将用来举剑的团队与用来降落地下城的团队结合起来,找出我们必须攻击巨魔的方式。
巨魔的例子尤其是耶稣会士,因为通常来说,要花几招才能完成,并且每次进攻都会得到随机结果。 由于我们的算法倾向于较短的通过时间,因此最好坚持对我们的战斗能力做出乐观的预测。
经过530,000次演练和10,600,000支球队(每场200支球队),我们终于找到了如何攻击巨魔的方法:
north, east, open window, into, west, light, lift trap, small hi, get, west, light, tug large, lift trap, down, north, stab
仍然有一些不必要的命令,我们仍然不知道我们必须多次击打他,但是我们可以处理它。
致命的嗜好
搜索算法不知道收集物体,扔物体和将玩家从一个房间移到另一个房间之间的区别。 他定义进度的唯一方法是查看历史进度的标记。
这在搜索算法中迅速发展出对...谋杀的嗜好! 要杀死玩家,尤其是因为它是如此的简单,请输入“ ATTACK”:
>attack [ ] , ! **** **** , , . , . c-. , .
在Mini Zorka中,第一个死亡不是游戏的结局,玩家会传送到另一个地方,并且您的物品分散了。 对于搜索算法,死亡只是对象从一个房间移动到另一个房间,并创建了沿故事移动的标记。 这种嗜好会导致游戏中其他有趣的bug出现,例如玩家将手扔进河里的能力。
根据解决难题和收集宝物的要求,游戏得分从0到350分。 玩家死亡时,他降低10点。 我们可以将帐户用作试探法,但这可以过分减少冒险行为-喜欢游荡到黑暗的地方或与巨魔作战。
搜索算法还对玩家看不到的内容非常感兴趣,例如NPC在房间之间移动。 例如,标记@ mv_112_37指示小偷向特定房间的移动。 搜索算法通过重复执行Z或WAIT命令来设法重现此标记,本质上是期望小偷到达目标房间。
他还喜欢在不同的地方捡起并扔掉物体,因为物体的每一次运动都是一个新的标记。 谁知道 也许把这片叶子扔在森林小径上会导致游戏胜利! (旁白:不,不会。)
模糊测试始终会识别程序中的错误,尽管这种游戏仍然存在,但它没有什么不同。 他在游戏一开始就想出了如何生成“ Clrthatrqdc”一词:
>tie up [ ] With a Clrthatrqdc!?!
这似乎是一个未初始化的变量,指示非文本数据。 Z-machine中压缩文本的编码主要是字母,因为您看到的随机垃圾不如尝试将二进制文件打印为ASCII时多。 (目前,这个词
在Google上只有两次 (
已经四次,大约是Transl。 )。
演练
为了赢得比赛,我们将不得不将被掠夺的物品拖回战利品箱,然后将所有物品塞进战利品箱。 我们的简单搜索算法会花很长时间才能发现这种行为,尤其是考虑到这种浪费时间和将对象从一个房间移动到另一个房间的趋势的时候。
将随机研究中的算法复杂化需要时间,因此在添加新功能时必须保持选择性。 我们也想避免游戏中的先验知识-换句话说,我们只想作弊一点。
如果您想尝试,
请查看GitHub上的源代码,该源代码使用
JSZM (Z-机器Daniel Daniellgenbauer的解释器)。有很多
游戏可用 (最多支持3个版本)。
也提供了已经使用Z机数十年的Graham Nelson的
Z机标准文档。
我是否需要在
8bitworkshop上添加Z-Machine支持? 让我知道!