图灵完备完整简易攻略
ETO-秦始皇
2025年09月20日 00:13

前言

计算机里所有的电子元件都可以基于一种叫做“与非门”(NAND gate)的基本元件而实现。在本游戏中,你将会面对一系列挑战,在求解谜题的过程中,走出从基础逻辑门通向算术单元、存储器等复杂元件的道路,并沿着这条道路最终学习如何搭建完整的处理器架构。完成所有主线关卡后,你将对处理器架构、汇编语言和电子元件彼此之间的具体联系产生更加深刻的理解。你也会了解高级编程语言中常见的条件判断、循环、函数等概念是如何在汇编和硬件层面具体实现的。

本游戏是基于一个强大的电路模拟器而开发的。这个电路模拟器允许你自由发挥想象力,以不同的解法通过各个关卡,或以自己喜欢的方式搭建属于自己的计算机。你可以随心所欲地在你的计算机上连接显示屏、计时器、声音元件等部件,也可以接收现实生活中的键盘和网络发送的数据。你甚至可以为你自己的计算机设计一套自己专属的汇编语言。

一个相当不错的游戏,UP还没学过计算机组成原理和数字电路,第一次玩起来还是有相当大的难度的说。想着做一个攻略记录一下学习的过程,于是时隔半年再次打开游戏,然后发现快忘完了喵呜。所以做攻略的时候其实是在考古之前的遗迹喵。有一说一这个玩的真的很上头呐,从与非门到处理器架构,听起来句超级帅好伐。虽然一路遇到很多困难,也想过放弃,最后还是一点一点坚持下来了。看着自己的架构一点点完善,指令越来越丰富,布线慢慢调整优美,真的非常有成就感呢,也希望你能够在这个游戏里面有所收获呐。

最后有点失落那个外星人通关了一点话都没有说,本来还想听个 congratulation 的说。另外攻略基于的版本是 0.1055 Beta 应该影响不大其实。本人的游戏存档可以在这里获得:https://github.com/ETO-QSH/ObsoleteProjectETO/TuringCompleteSaves。存档路径:C:\Users\{YourName}\AppData\Roaming\Godot\app_userdata。以后有时间我应该会在我的架构上进一步进行扩展,写一个小游戏,最终想办法搓一个类似小游戏机的东西出来呢,也算是一个留恋吧。游戏中有什么疑问也可以在评论区贴出来,如果我能够解决我也会去尽可能帮助的呐。


第一章:基础逻辑电路

1. 原力觉醒

恭喜恭喜,你被绑架了!

我们将对你展开生命体智力测试。

测试规则很简单,造一台电脑就行。我们将会吃掉不具备这种智力的生物。祝你好运。

2. 与非门 (NAND)

你在上个测试中发挥得不错!

我们因此初步认定你大概不是一种植物。

正确!你成功解锁了与非门(NAND)。利用这个元件,你就能造出电脑里所有的东西了!

3. 非门 (NOT)

既然你已经解锁了与非门,那么接下来你就可以开始学着搭建一些电路了。

上一关里,你填好了一个与电路的输出相匹配的真值表。这一关里,你的任务是搭建一个与给定的真值表匹配的电路。

4. 与门 (AND)

眼下,在地球上所有接受测试的对象中,大象的成绩遥遥领先。考虑到你们大脑的尺寸差异,你做得其实也还不错。

5. 或非门 (NOR)

地球上大多数生物充满了攻击性,也不知道怎么集中注意力。

要想成功通过我们的测验,你就要学会逻辑思考,不能只想着搞破坏。

6. 或门 (OR)

高兴点,地球人。能参与我们的实验是你的荣耀。

你可是获得了与银河系中最先进的文明对话的良机。

7. 高电平

8. 第二刻

你也知道,我们进行的这一系列测试,最终的成果将是一台完整的电脑。

按照我们的法律,能完成这一任务的生物会被认定为具有基本的知觉。

这是我们考虑不吃掉你的首要原因。

9. 异或门 (XOR)

10. 三路或门

11. 三路与门

12. 同或门 (XNOR)


第二章:算数运算&存储器

13. 二进制速算

这关是我最喜欢的消遣小游戏。在规定时间里把十进制数转成二进制数。

14. 成对的麻烦

我们的科技非常先进,连叠袜子这样的事情都是机器自动完成的。但是不巧,叠袜子机上给袜子配对的检测器刚才坏掉了。

15. 奇数个信号

16. 循环依赖

在我们的教育系统中,传统的教学方法是骗学生走错误的路,然后对他们发出大声嘲笑。

我不清楚这对学生有没有好处,但是老师们都很喜欢这么干。

17. 信号计数

18. 半加器

我们用数字丈量宇宙。所以你造的电脑必须学会计数。

19. 延迟线

20. 加倍

21. 全加器

22. 奇变偶不变

上一关里,你已经知道了我们不允许电路中存在循环依赖。现在你需要掌握一种例外情况。

23. 1 位开关

24. 1 位取反器

我们正在试验背景图像如何影响地球生物的认知功能。

25. 8 位或

也许你会觉得把无法通过测试的所有地球生物都吃掉是不道德的?

但事实上这不构成什么伦理问题,因为你们都是很好的野生动物,对我们来说珍惜野味是种美德。

26. 8 位非

我们先前的数学模型使用大脑体积来作为智力高低的主要判据。现在看来,这个模型还是过于简单了。

制造和使用工具的能力在智力的早期发展过程中起着决定性的作用。

所以很显然,胳膊的数量才应该是智力的主要判据。你知道吗?地球上有种海洋生物有八条胳膊,它们在我们的测试里表现得更好。

27. 8 位加法器

28. 负数

要知道事物之间的差异,你需要减法。而要得到减法,首先你需要负数。

29. 数据选择器

虽然他没能通过我们的测试,但我们最终决定留下他的狗。和其他的地球生物不同,狗狗毛茸茸的,还能遵守简单的命令。

我们也许会要你们俩组队,因为你们的优缺点正好彼此互补。

30. 相反数

31. 总线

32. 优雅存储

延迟线允许我们将一个输入值暂存1刻。不过一个能将输入值保存更长时间的元件会更有用。

我们希望你能搭建这么一个元件。

33. 存储一字节

34. 1 位解码器

35. 3 位解码器

我们让实习生给这个元件添加了一个“禁用”位。我们受不了他总是四处转悠、恳求我们给他一点无聊乏味的活儿来做。

36. 逻辑引擎

37. 小盒子

你能在这有限的空间里塞下4个字节的寄存器吗?

在我们的先进文明中,强迫囚犯做极其琐碎的工作是奴役行径,技术上讲这是不合法的。所以我们让我们的实习生为你的组件创建了一个256字节的版本。

38. 计数器

计数是一项昆虫也具备的基本能力。有了计数能力,生物就有了进行比较和算术的能力。然后在不知不觉间,猴子们也就能学会制造电脑了。

搭建一个元件,使其每一刻输出的数值都会自动增长。


第三章:处理器架构

39. 算数引擎

40. 寄存器之间

是时候开启你的主要项目了,从现在开始,一步步搭建『OVERTURE』计算机架构吧。它实实在在地是一台图灵完备的机器,无论从什么角度讲都称得上是一台真正的计算机!

我把这一关中红色元件的位置锁定了,因为你的布线总是乱糟糟,没有留下足够的空间。从现在开始,你设计的这些乱七八糟的电路会在各关卡之间同步,这意味着你不再需要每关都从零开始。

41. 元件工坊

本关并不是一个挑战关卡,而是一个工具性关卡。你随时可以选择回到关卡选择界面,继续完成后续任务。

42. 指令解码器

你之前在“寄存器之间”一关中建立的电路可以在寄存器之间复制数值,而在“算术引擎”一关中建立的电路可以对2个输入做不同的算术运算。但在后续的关卡中你将需要在同一个电路中同时进行这两种操作。要做到这一点,你需要建立一个“解码器”。它能根据指令中我们尚未使用的那两位数值,来决定我们的计算机处于何种模式。

43. 计算单元

这一关里,所有的寄存器都拥有一个额外的输出引脚。这个输出引脚会无视读取引脚的输入,始终输出寄存器中存储的数值。

44. 条件判断

45. 程序

46. 立即数

47. 图灵完备

到目前为止,我们所有的程序都只能逐字节地按顺序执行。

在之前的关卡中,只有代码能影响数据,现在也该是时候让数据来影响代码运行了。添加了条件跳转的能力后,我们的电脑就能运行任何算法,完成一切可行的计算了。

你居然成功了,地球人!我本来以为你不过是看起来很奇怪的某种无毛猿类,但你确实造出一台真正的电脑来了,挺厉害!


第四章:编程

48. 加 5 等于几

你已经搭建好第一台计算机的硬件架构了,不过要想通过我们的测试,你还需要借助它完成走迷宫的测验。

只是鉴于你还不知道怎么在这台计算机上编程,目前你还没法完成这种挑战。

因此我们从我们的飞船上替你找了些差事,供你练手。

49. 激光炮直瞄

我们的飞船通常使用激光来摧毁接近的小行星。

为了校准激光炮,我们需要你借助复杂的数学公式来计算出小行星的周长。

2×π×r

半径 r 是输入值。

你可以将 π 近似为 3 。

计算完成后,请将结果发送到输出设备上。

你现在可以使用汇编代码编写你的程序了。汇编代码允许你在编辑器里为指令取一个别名,例如你可以用“add”代替“68”来表示加法。

汇编别名:

add --> 0b01000100 (68)

copy --> 0b10000000 (128)

io --> 0b00000110 (7)

程序代码:

# 1号寄存器 --> R

copy|io*8|1 # 0b10110001 (177) # 2号寄存器 --> R copy|1*8|2  # 0b10001010 (138) # 3号寄存器 --> 2R add         # 0b01000100 (68) # 1号寄存器 --> 2R copy|3*8|1  # 0b01011001 (89) # 3号寄存器 --> 3R add         # 0b01000100 (68) # 1号寄存器 --> 3R copy|3*8|1  # 0b01011001 (89) # 2号寄存器 --> 3R copy|3*8|2  # 0b01011010 (90) # 3号寄存器 --> 6R add         # 0b01000100 (68) # 输出 6R 结果 copy|3*8|io # 0b01011110 (94)

50. 太空入侵者

我们飞船的货仓里了进了几只太空老鼠。

我们已将你的计算机连接到了我们的高科技机器人上,你的任务是给机器人编程,让它发射激光来清除太空老鼠。

注意,上一束激光仍在空中飞行时,机器人是无法发射新的激光的。

如果你想知道如何为机器人编程,请参阅机器人操作指南。代码编辑器里也有指向该手册词条的链接。

汇编别名:

eq_zero --> 0b11000001 (193)

程序代码:

# 机器人操作常量定义

const left 0

const step 1

const right 2

const sleep 3

const enter 4

const tap  5

# 来到就绪位置

tap copy|io step copy|io

# 停留循环

label sleep_loop

sleep copy|io   # 等待

# 观察节点

label tap_loop

copy|io*8|3    # 输入至reg3

sleep_loop eq_zero # 观察到0继续停留

tap copy|io    # 发射

copy|2*8|3     # 清空reg3

tap_loop eq_zero  # 跳回进行观察

51. 密码锁

储藏室的保险门坏了,我们的老清洁工被锁在了里面。

这扇门总是无缘无故地改变密码,因此我们需要一个可以随时恢复密码的程序。

找到密码的最简单方法是尝试所有的组合,直到你找到正确的密码。

另外,当你猜测的数值过高时,这个坏掉的锁会发出奇怪的哗哗声。利用这一点,你或许可以找到更高效的解法。

52. 时间掩码

在我们星球上每个星期有 4 天,分别是星期零,星期壹,星期贰和星期叁。我听说有的地球人会把星期贰的日子算错?

我对此并不感到奇怪。

不管怎么说,新年就要到了。我们需要你来算一下每个人的生日都在一星期里的哪一天。我会给你日期,你只需要在8个时钟刻内给我报上那是星期几就行。

53. 迷宫

传说中的迷宫。如果你解决了这个难题,你就通过了测试!

程序代码:

# 左手法则

label go

step copy|io # 前进

left copy|io # 左转

# 观察环境

label see

copy|io*8|3  # 观察前方

go eq_zero  # 没有障碍物就跳回前进

right copy|io # 否则右转回去

enter copy|io # 有门自然会开

see always  # 无条件跳转


第五章:处理器架构 2

54. 异或

汇编别名:

or --> 0b01000000 (64)

nand --> 0b01000001 (65)

程序代码:

# 读取输入,进行按位或

copy|io*8|1 copy|io*8|2 or

# 进行按位与非

copy|3*8|4 nand 

# 进行按位与

copy|3*8| 1 copy|4*8| 2 and

# 输出(原理见:异或门 (XOR))

copy|3*8|io

55. 8 位常数

56. 8 位异或

57. 相等

58. 无符号小于

59. 有符号小于

60. 宽指令

61. 一把线,像挂面

终于是时候让你构建『LEG』体系了!

62. 操作码

63. 立即数

64. 条件判断 2

恭喜,你已经实现了『LEG』计算机的全部功能!

我将逐步向你展示一些可能的升级操作,直到你实现函数调用功能为止。但从今往后,一切实现细节由你自己决定,我不会再要求你应该使用什么操作码,也不会给你施加其他诸如此类的限制。


第六章:函数

65. 十六进制速算

这关是我第二喜欢的消遣小游戏。在规定时间里把十进制数转成十六进制数。

66. 移位

除了左移元件以外,我们还找了个实习生,让他帮你解锁了右移元件。他的工作很简单,把你的电路图镜像翻转一下就行了。

我推荐把左移和右移功能添加到你的计算机硬件里,以便在后续的关卡里使用。

67. 随机存储器

汇编别名:

i --> 0b10000000 (128)

j --> 0b01000000 (64)

add --> 0b00000000 (0)

sub --> 0b00000001 (1)

read --> 0b00110000 (48)

write --> 0b00110001 (49)

eq --> 0b00100000 (32)

neq --> 0b00100001 (33)

xq --> 0b00100010 (34)

dq --> 0b00100100 (36)

deq --> 0b00100101 (37)

pop --> 0b00110010 (50)

push --> 0b00110011 (51)

io --> 0b00000111 (7)

程序代码:

# 初始化数组长度

i|j|add 32 0 2

# 循环读取数据至内存

label input

i|add 0 io 5

write 5 3 0

i|add 1 3 3

j|sub 2 1 2

dq 2 0 input

# 重新初始化寄存器

i|j|add 32 0 2

i|j|add 0 0 3

# 循环读取内存以输出

label output

read 0 3 5

i|add 0 5 io

i|add 1 3 3

j|sub 2 1 2

dq 2 0 output

68. 延迟量

所有元件都有一个延迟量。一个电路中,总的延迟量是由延迟最严重(速度最慢)的那条路径决定的。为了减小延迟量,你可以把逻辑门并行排列,使它们能同时进行运算。在本关里,你要向我证明你能够理解这些概念。

69. 半字节乘法

将两个 4 位数字相乘,便可以得到最多 8 位的乘积。设计一个电路,实现此乘法功能。

你刚才已经设计出了两路 4 位输入的乘法装置。我们让我们的实习生免费把它扩展成了 8 位乘法器。

70. 栈

为了削减开支,我们决定改变服务窗口的排队制度,以减少来访的人数。我们将用“先来后服务”的模式代替原先的“先来先服务”模式。试想一摞叠得高高的文件,公民们只能把提交的文件放到最上面(称压栈,即PUSH),而办事的员工也从最上面拿走文件开始处理(称弹栈,即POP)。这种数据结构的名称叫栈(stack),我们希望你能够在硬件层面实现它。

71. 实验室

欢迎来到实验室。和元件工坊一样,这不是一个主线关卡,而是我们为你提供的工具性关卡。

在出错的硬件上编程会很麻烦。一边编程,一边还要排查电路中的错误,这种体验非常痛苦。你会忍不住去随手修复一下硬件上的问题,以便继续回头写代码。但这些硬件层面的改动很可能又会弄坏别的功能。所以在开始编程前,尽量确保你的硬件能做到100%可靠吧!

另外,因为你已经完成了『LEG』架构,我替你解锁了沙盒中的 16 位、 32 位和 64 位元件。

72. 除法

程序代码:

# 读取被除数和除数

i|add 0 io 2

i|add 0 io 3

label divmod

# 如果被除数小于除数跳出进行输出

xq 2 3 24

# 用被除数减去除数

sub 2 3 2

j|add 4 1 4

# 否则重复减去除数

deq 2 3 divmod

# 输出商和余数

add 4 0 io

add 2 0 io

73. 压栈与弹栈

程序代码:

label main

j|add io 0 2 # 读取输入

eq 1 2 16   # 为 0 出栈否则入栈

# 入栈分支

push 2 0 0

eq 0 0 main

# 出栈分支

pop 0 0 io

eq 0 0 main

74. 函数

我们最近的经费预算有点紧张,只能给大家降薪,结果现在实验室的助手们都罢工了。所以,这一关卡里你需要亲自评估设计的成果。当然,这也能让我们测试你的可信度和成熟度。

讲道理这个题写不写都不影响后面的挑战

call和ret完全用不上的说,我第一次通关也是直接跳过的喵

但是如果想搞我也给出我的设计方案呐,就是一套下来东西怪多的说

因为没有官方的测试,我还编写了一段递归斐波那契数列方便测试

以及搞了一个时尚小垃圾方便可视化结果呢

汇编别名:

call --> 0b00110100 (52)

ret --> 0b00110101 (53)

程序代码:

label main

i|j|add 0 6 1 # 索引计数

call fib 0 0  # 函数调用

i|add 0 2 io  # 结果输出

label fib

i|add 0 1 3

j|dq 3 2 else

i|j|add 0 1 2

ret 0 0 0

label else

push 3 0 0 

push 4 0 0

push 5 0 0

# 计算fib(n-1)

j|sub 3 1 3

i|add 0 3 1

call fib 0 0

pop 0 0 5

pop 0 0 4

pop 0 0 3

i|add 0 2 4

push 3 0 0 

push 4 0 0

push 5 0 0

# 计算fib(n-2)

j|sub 3 2 3

i|add 0 3 1

call fib 0 0

pop 0 0 5

pop 0 0 4

pop 0 0 3

i|add 0 2 5

# 返回结果

add 4 5 2

ret 0 0 0


第七章:汇编挑战

75. AI 打牌

NAK 02 是我们的智能工程机器人。它很聪明,但有些时候会耍流氓,甚至在飞船上煽动叛乱。

这一回它又占据了飞船主控室,还劫持了船长。

它唯一的弱点是好赌。我们已经吸引了它的注意力,让它跟你来打牌。它跟我们保证,如果你赢了,它就投降。

一定要赢,你是我们唯一的希望了!

76. 机器赛跑

机器人竞赛是飞船上最受欢迎的运动。不同程序控制的机器人需要完成同一组障碍赛。在完赛的程序中,谁的代码量最少,谁就是赢家。

这次你控制的机器人叫Fastbot,他看不到面前的东西,但它可以同时完成转身和前进的动作。另外,它还有双帅气的红色跑鞋。

程序代码:

# 如果开10kHz,会出现“量子隧串效应”

# 最后6个码可以不用写,从64优化到58喵

3 0 1 0 0 3 2 3 0 3 2 2 1 2 3 3

0 3 2 3 3 0 1 0 3 0 1 1 2 1 0 0

0 3 2 3 3 0 1 0 3 0 1 1 2 1 0 1

1 2 3 2 2 1 0 1 2 1 1 0 0 3 0 1

77. 新品上市

你们星球上最令人难忘的是水果,它们确实很美味。

因此我们要在食堂举办一个水果尝鲜活动。

但我们要确保不会两次送上同样的水果供人品尝,不然场面会很尴尬。

程序代码:

# 走到操作台(是不是有点太远了)

i|j|add 0 0 io

i|j|add 0 1 io

i|j|add 0 0 io

i|j|add 0 1 io

i|j|add 0 1 io

i|j|add 0 1 io

i|j|add 0 1 io

i|j|add 0 0 io

i|j|add 0 1 io

i|j|add 0 2 io

i|j|add 0 1 io

# 轨道常数 92

i|j|add 92 0 5

# 思路是将出现过的数字在RAM对应位置记录

# 如果记录过则说明出现过

# 这个方法可以在内存充足的时候高效排重

label main

j|add io 0 1  # 观察前方

eq 5 1 wait  # 如果是轨道就等到

read 0 1 2   # 否则读取内存地址

eq 5 2 wait  # 如果值为轨道等待

neq 2 4 break # 同时不为 0 则说明水果出现过

write 1 1 0  # 否则将水果数值写入对应地址

# 等待等待

label wait

i|j|add 0 3 io

eq 0 0 main

# 跑去按按钮

label break

i|j|add 0 2 io

i|j|add 0 4 io

78. 美味排序

我们正在为银河系的食物百科全书编写有关人类食物的条目。我们的语言中没有字母表,因此百科全书中的条目是按美味程度排序的。

程序代码:

# 方法一:

# 经典的冒泡排序算法,时间复杂度:O(n^2)

# 同时使用了n(15)个RAM位置存储数组

# 现将输入全部读取在内存中

label input

i|add 0 io 1

write 1 3 0

i|add 1 3 3

i|dq 15 3 input

# 记录排序指针

i|j|add 0 15 1

# 重置指针以及缩短边界

label wait

j|add 0 1 0

i|j|sub 0 1 2

i|j|add 0 0 3

j|sub 1 1 1

i|eq 0 1 output

# 向右读取两个数字

label main

i|add 1 2 2

i|add 1 3 3

read 0 2 4

read 0 3 5

eq 1 2 wait   # 如果指针到达边界

dq 4 5 rec   # 如果左边大于右边

eq 0 0 main   # 否则指针向前推

# 交互两个元素的位置

label rec

write 4 3 0

write 5 2 0

eq 0 0 main

# 将答案逐个输出

label output

read 0 1 io

i|add 1 1 1

eq 0 0 output

# 方法二:

# 思路是用RAM开集合

# 优点是时间复杂度只有O(n)且代码实现简单

# 缺点是输出的时候要遍历整个RAM

# 数据较少的时候利用率低

label input

i|add 0 io 1

# 对应地址位数值加加

read 0 1 0

i|add 1 0 0

write 0 1 0

# 循环读取输入

i|add 1 2 2

i|dq 15 2 input

add 0 0 1

# 遍历RAM进行输出

label output

read 0 1 2

i|add 1 1 1

i|eq 0 2 output

# 按照出现的次数(RAM数值)多次输出

label while

j|sub 1 1 io

j|sub 2 1 2

j|dq 2 0 while

eq 0 0 output

79. 跳舞机器

我们都喜欢机器人在舞池中的动作。因此我们希望他能带领我们的舞蹈队。

唯一的问题是如何让他想出原创的舞蹈序列。

你或许会问,如何从决定性的逻辑中诞生出创造性的力量?

答案是通过伪随机数生成器。

汇编别名:

and --> 0b00000010 (2)

rol --> 0b00000110 (6)

ror --> 0b00000111 (7)

程序代码:

# 经典的RPNG随机数算法

# 我这里使用rol和ror,而不是shl,shr

# 主要原因的我的ALU被塞满了果咩(虽然好多都用不上)

# 前者实现后者的效果只需要AND与一下进行掩膜

# 而后者会完全丢失数据,所以我的ALU采用的是前者

# 如果你不想怎么麻烦可以直接把ALU里面对应的元件进行替换即可

i|add 0 io 1  # 随机数种子

label prng

j|ror 1 1 2

j|and 2 127 2

xor 1 2 3   # step 1

j|rol 3 1 4

j|and 4 254 4

xor 3 4 5   # step 2

j|ror 5 2 2

j|and 2 63 2

xor 5 2 1   # step 3

j|mod 1 4 3

i|add 0 3 io  # step 4

eq 0 0 prng

80. 核金汉诺塔

我们需要你帮忙清理一下地下室。

我们想让你从旧的反应堆之中取出具有放射性的碟片,并将它们按顺序叠好。请不要将较大的碟片摞在较小的碟片之上,否则反应堆将会爆炸。

方法一(不使用函数,而是压缩指令集):

汇编别名:

shift --> 0b00110110 (54)

程序代码:

# 读取输入建立映射表

i|add 0 io 3

i|add 0 io 0

i|add 0 io 1

i|add 0 io 2

shift 1 # 切换至二位码模式

# 先进后出数据栈

push 1 push 0

push 1 push 2 push 0 push 2

push 1 push 0 push 2 push 1

push 2 push 0 push 1 push 0

push 1 push 2 push 0 push 2

push 0 push 1 push 2 push 1

push 0 push 2 push 1 push 0

push 1 push 2 push 0 push 2

push 1 push 0 push 2 push 1

push 2 push 0 push 1 push 0

push 2 push 1 push 0 push 2

push 0 push 1 push 2 push 1

push 2 push 0 push 1 push 0

push 1 push 2 push 0 push 2

push 1 push 0 push 2 push 1

push 2 push 0 push 1 push 0

shift 0 # 切换至四位码模式

# 数据循环出栈

label for

pop 0 0 io

i|j|add 0 5 io

eq 0 0 for

方法二(使用函数,进行递归操作):

程序代码:

# 具体代码可以查看这个视频

# 网页链接​

# 对应思路抄过来的说不想努力了喵

# 讲道理还是我上面那个写法比较帅喵

const catch 5

j|add io 0 1

j|add io 0 2

j|add io 0 3

j|add io 0 4

label main

call move 0 0

eq 0 0 main

label move

j|eq 1 0 zero

push 1 0 0

call move_1 0 0

pop 0 0 1

call move_0 0 0

push 1 0 0

call move_2 0 0

pop 0 0 1

label end

ret 0 0 0

label zero

call move_0 0 0

eq 0 0 end

pop 0 0 1

ret 0 0 0

label move_0

j|add 2 0 io

i|j|add catch 0 io

j|add 3 0 io

i|j|add catch 0 io

ret 0 0 0

label move_1

j|sub 1 1 1

j|add 3 0 5

j|add 4 0 3

j|add 5 0 4

call move 0 0

j|add 3 0 5

j|add 4 0 3

j|add 5 0 4

ret 0 0 0

label move_2

j|sub 1 1 1

j|add 2 0 5

j|add 4 0 2

j|add 5 0 4

call move 0 0

j|add 2 0 5

j|add 4 0 2

j|add 5 0 4

ret 0 0 0

81. 行星之名

我们让实习生用人类的文字来输入星球名称,可惜他忘记将每个名称的首字母大写了。

程序代码:

# 初始化变量

i|j|add 32 0 2

i|j|sub 0 1 3

# 读取字符

label main

i|add 0 io 1

j|add 3 1 3

# 判断字符类型

eq 1 2 jump

eq 3 4 first

# 非首字母小写

i|add 0 1 io

eq 0 0 main

# 非法字符跳过

label jump

i|j|add 32 0 io

i|add 0 io 1

sub 1 2 io

eq 0 0 main

# 首字母大写

label first

sub 1 2 io

eq 0 0 main

82. 水世界

好消息,我们要把地球变成一个异星的水上乐园!

我们需要你帮助我们为“海盗瀑布”水滑梯找到一个合适的地点。具体地说,我们正在寻找一个能容纳大量水的地方。

程序代码:

# 算法:双指针接雨水

# 这个算法采用双指针法,通过一次遍历数组

# 利用两个指针分别从数组两端向中间移动

# 同时维护两个变量分别记录当前指针左侧和右侧的最大高度

# 根据最大高度的大小关系,动态结算当前指针位置的雨水量

# 并相应移动指针,直到两个指针相遇

# 这种方法将时间复杂度优化到 O(n),空间复杂度优化到 O(1)

# 循环读取数组 - h

label input

i|add 0 io 2 # 读取输入到寄存器

write 2 1 0 # 寄存器写入到RAM

i|add 1 1 1 # 读取计数,地址加加

i|dq 16 1 input # 读取16个退出

# 初始化变量

i|j|add 0 0 1 # result

i|j|add 0 0 2 # left

i|j|sub 16 1 3 # right

# do-while主循环

label while

read 0 2 4 # h[left]

read 0 3 5 # h[right]

deq 4 5 else # h[left] < h[right]

j|read 0 16 5 # leftMax

xq 4 5 else_1 # h[left] < leftMax

j|write 4 16 0 # leftMax = h[left]

eq 0 0 out_1 # 无条件跳出

label else_1

add 1 5 1 # res += leftMax

sub 1 4 1 # res -= h[left]

label out_1

j|add 2 1 2 # left ++

eq 0 0 out_3 # 无条件跳出

label else

j|read 0 16 4 # rightMax

xq 5 4 else_2 # h[right] < rightMax

j|write 5 16 0 # rightMax = h[right]

eq 0 0 out_2 # 无条件跳出

label else_2

add 1 4 1 # res += rightMax

sub 1 5 1 # res -= h[right]

label out_2

j|sub 3 1 3 # right --

label out_3

xq 2 3 while # left < right

# 输出结果

i|add 0 1 io

C语言:

#include <stdio.h>

int main() {     int heightSize = 16;     int height[] = {4, 6, 1, 4, 6, 5, 1, 4, 1, 2, 6, 5, 6, 1, 4, 2};     int leftMax = 0, rightMax = 0; // 分别记录左侧和右侧的最大高度     int left = 0, right = heightSize - 1; // 左指针和右指针     int result = 0; // 用于存储结果     do {         if (height[left] < height[right]) { // 如果左侧的高度小于右侧的高度             if (height[left] >= leftMax) { // 更新左侧的最大高度                 leftMax = height[left];             } else { // 左侧结算                 result += leftMax - height[left];             }             left++; // 左指针右移         } else { // 如果左侧的高度大于等于右侧的高度             if (height[right] >= rightMax) { // 更新右侧的最大高度                 rightMax = height[right];             } else { // 右侧结算                 result += rightMax - height[right];             }             right--; // 右指针左移         }     } while (left < right); // 当左指针小于等于右指针时,继续循环     printf("Trapped water: %d\n", result);     return 0; }


附录

最终完整指令集:

最终处理器合影留念: