从AI打牌到汉诺塔:图灵完备游戏攻略详解
从AI打牌到汉诺塔:图灵完备游戏攻略详解
《图灵完备》是一款考验玩家编程思维和逻辑推理能力的游戏。本文详细介绍了游戏各个关卡的通关思路,包括AI打牌、机器赛跑、新品上市、美味排序、跳舞机器、核金汉诺塔、行星之名和水世界等。每关的攻略都经过精心整理,旨在帮助玩家更好地理解游戏机制,顺利通关。
AI打牌
规则:总共12张牌,每人每次轮流可以取1-3张牌,取走最后一张牌的人失败。
这一关是先手必赢的,核心思路是留下5张牌给对方取。这样无论对方取1张还是3张,都可以通过取剩余的牌获胜。
开局直接取三张,剩下5+4张,对方随意取多少张,只要剩五张给他,就能赢了。
机器赛跑
规则:机器人没有视力,无法看到面前的是墙还是道路,但他有一双帅气的红色的跑鞋,达到终点即为胜利,代码量越少你的比赛名次越高。(游戏中没有比赛名次系统,但并不影响人们追求最少的代码量,代码量少还可以完成一个成就)
这一关的地图都是由一个形状对称旋转分布的:
将地图分成四份我们可以看到将左下角的部分进行旋转后就能得到其他部分:
机器人所在的第一个模块称为0号模块,
顺时针旋转90°后就成为了机器人右边的模块,称之为1号模块
顺时针旋转180°后,我们称之为2号模块
顺时针旋转270°后,我们称之为3号模块
机器人的操作指令为:
根据上面的指令,我们可以得出,机器人通过模块的操作为
0号模块:301
1号模块:012
2号模块:123
3号模块:230
但是机器人每次进入一个模块的入口都可能不同,以0号模块(机器人所在的模块)为例,他可以从左边进入模块,也可以从右边进入模块,比如机器人右边的1号模块,他就是从右边入口进入模块的,而从另一边进入模块,我们的操作就截然不同了,由此得出:
在从另一边进入模块的情况下,操作就变为
0号模块:321
1号模块:032
2号模块:103
3号模块:210
水平翻转0-3模块,我们依次命名为4-7号模块
水平翻转0号模块称为4号模块,
水平翻转1号模块称为5号模块,
水平翻转2号模块称为6号模块,
水平翻转3号模块称为7号模块
最后还有一个问题,就是通过一个模块后,怎么进入下一个模块的起始地点?
怎么从第一个模块的终点走到第二个模块的起点呢?
这个问题的想法是直接预存,就是将这个操作预先输入到内存,然后依次读取进行操作,例如机器人从左下角第一个模块的终点要走到右边第二个模块的起点。需要向右走一步,则要输出0,将这个步骤连同地图模块顺序一起存起来即可。
例如:
机器人要开始走0号模块,则储存 ?0(因为没有第一步,所以?处可以填写任意数值)
机器人走完第一个模块(0号模块)后到达图片下方的红色箭头左边待命,此时需要让他向右走,然后通过5号模块,则储存 05
05的第一位数字为第一步的方向,第二位数字为要通过的模块号。
上图的大模块可以存储为:?0,05,35,22
运行代码时,先将第一步数据和模块号写入ram内存(总共要写16条,这也是代码长的主要原因),随后依次读取,将数据除以10后,就能分别得到第一步数据和当前模块号。
走模块时先根据第一步数据走出第一步,随后根据模块号决定走法,
0号模块则依次输出3,0,1 ,这个可以固定为常数
1号模块则在0号模块的基础上常数+1,然后对4取余,依次输出0,1,2
2号模块常数+2,三号模块常数+3
但对于4号及以上就要走第二步时再次+2,建议是多写一个行走函数,模块号大于4时就调用这个,
将输出的常数改为3,2,1,然后操作相同,循环函数即可通关。
新品上市
这个比较简单,先将机器人送到传送带前,然后读取传送带的信息,传送带为92,读到这个则输出发呆,读到其他东西则先依次和内存中的数值进行比较,全都不一样则保存到内存,一样则右转交互一下,左转继续工作(这一关bug较多,可以是由bug通关法)。
美味排序
这一关和新品上市大同小异,先读取15次数值到内存(不可检测0,因为0也是数值之一),然后将一个寄存器设置为255,依次进行比较,如果读出的数值比寄存器中的小则将小的数值放入这个寄存器中,并记录这个数值的内存地址,如果比寄存器中的大,则不操作继续读,以此循环15次,即可得出最小值和最小值的地址,输出最小值,然后将最小值的地址的数值更新为255(防止重复),循环即可通关。
跳舞机器
略(这关你不会都想要看攻略吧?)
核金汉诺塔
伪代码照着写并不难,这一关的难点主要在如何传递参数,官方建议是可以压入栈内,随着地址一起弹出来,但我觉得这个已经算复杂了,因为栈的操作是后进先出,很容易乱,所以我优先推荐将参数写入内存里,空出一个寄存器用于保存这是第几个move调用,每写入一次数据(4个参数),让寄存器加1。
第三行move disk from source to dest和最后一行move(disk_nr - 1,spare,dest,source)运行结束则代表着一个move函数调用结束,要在函数后面ret前进行寄存器-1操作。
若想用官方的栈方法,则要注意不要让数据和地址混乱了,先将数据反着(4321)压入栈内,然后调用时(在if之前),先弹出地址!,保存在寄存器里,然后正着(1234)弹出数据更新在寄存器里,然后反着压回数据(因为这时候函数调用没有结束,此数据还有作用!),再将地址压回栈内。
第五行move(disk_nr - 1,source,spare,dest)和最后一行move(disk_nr - 1,spare,dest,source)的后面函数都要进行删栈操作,不用弹出地址,因为地址已经因为ret弹出了,随后更新栈的数据到寄存器中(要先弹出地址)!
温馨提示:每一次move调用的参数均不同,注意压栈顺序!
行星之名
此关十分简单,只需将输入的ASCII码全部写入内存(通关判断是否为0判断数据是否结束),依次读出,然后将第一个字母大写(数值-32)输出,然后小写正常输出,并检测是否为空格(值为32),如果是则先输出,然后将下一个字母大写输出即可,读出内存为0时即代表真个数组已经输出完了,可结束再次从头循环主程序。
水世界(亿点点难)
我的想法是首先读入地形数据,
然后开始时开始循环检测坑(能装水体的地方)前的最高点(如果右边地形比左边高,则继续用右边的地形和右右边的地形比较,直到右边的地形比左边的矮),即左边第一个箭头,找到最高点时,储存起来,我将这个点称之为峰,第一个峰左边是完全没有坑(能装水体的地方)的,所以可以忽略。
随后从第一个峰开始依次读取右边地形信息寻找比峰高或者和峰一样高的第二峰,在此过程中,将比峰矮的地形压入栈内(用于后面计算水体数量),第二峰的高度此时也会一起压入栈内。
如果寻找到了比峰高或者和峰一样高的第二峰,则先将第二峰的高度存起来,用峰减去栈内保存的地形,累加得出此区域能装的水体数量,随后将峰的数值替换为第二峰的数值继续寻找下一个第二峰。
那么峰比第二峰低的水体区域怎么解决?
当峰比第二峰高时,循环会读取到地形外,即为0,此时需要反过来循环遍历峰到地形外的最高点,将其指定为第二峰。随后将峰的高度替换为第二峰的高度再次遍历累加即可。
但这样什么时候是个头呢?怎么判定结束呢?此时需要在循环会读取到地形外时,进行一次判断,峰到地图外是否都为下坡(即遍历是否左边的地形都比右边的高),也就是一开始的图的右边下箭头,如果一直到地形外都是如此,那就可以判定结束,输出最终累加的水体数量完成关卡,再次进入主循环开始进行下一关。
感谢你能读到这里,第一次写稿,写的不好请见谅,如果写的不对或者不够详细的地方还请指出,我会进行改正的。
仅以此纪念《图灵完备》,纪念在电脑前苦思冥想的日子。
敬你,敬我,敬我们
敬,不完美的明天
2024/8/1