先翻译题目:
逃离迷宫
计算机被困在火星上的迷宫中。编写一个程序,让它逃离迷宫。
计算机配备了连接的轮子和前方障碍物探测器。与轮子和探测器的输入/输出是内存映射在地址7FFF上:
对外设的输出信号:
位 设置为1代表:
2 向前移动(1步)
3 向左转(90度)
4 向右转(90度)
移动/转向在位从0变为1时开始,但需要一段时间才能完成。
从外设输入:
位 当为1时
8 前方探测到障碍物
9 设备正在转向
10 设备正在向前移动
帮助信息的翻译:
汇编语言快速参考
语法为 destination = calculation ; jump-condition 目标和跳转条件是可选的。
D 和 A 是两个寄存器。*A 表示 RAM 中地址所包含的值。
示例:
D=D+1 计算 D+1 并将结果存储在 D 中。
D-1;JGE 计算 D-1。如果结果大于 0,则跳转。(结果不被存储。)
A = 1234 将数字 1234 存储在 A 寄存器中。
# Hello 注释 - 编译器忽略
计算
D + A
D-A 或 A-D
D&A(按位与)
D|A(按位或)
A+1 或 D+1
A-1 或 D-1
-A 或 -D
~A 或 ~D(按位反转)
1 或 0 或 -1
在所有情况下,可以使用 *A 代替 A。
目标
D、A 和 *A 的任意组合都可以用作目标。多个目标用逗号分隔,例如 D,A = 1。
跳转条件
当计算结果为时跳转:
JEQ 等于 0
JNE 不等于 0
JGT 大于 0
JGE 大于或等于 0
JLT 小于 0
JLE 小于或等于 0
JMP 无条件跳转(不管计算结果如何)。
数字指令
可以直接将数字赋给 A。例如:A = 47。
十六进制数以 0x 为前缀,例如:A = 0x7FFF
二进制数以 0b 为前缀,例如:A = 0b010111。
可以使用下划线来分隔数字组,例如:A = 0b_0101_1100。
注释
以 # 开头的行会被编译器忽略。可以用于注释和文档。
标签
关键字 LABEL 后跟一个名称,使名称代表下一条指令的地址。可以在跳转之前将该地址分配给 A,例如:A = LOOP
定义
关键字 DEFINE 后跟名称和数字,当它出现在其他指令中时,会将名称替换为数字。例如,以下两行:
DEFINE foo 0X7FFF
A = foo
等同于:A = 0x7FFF
多目标
可以将结果分配给多个寄存器。
例如 D,A = D - *A 计算的结果将同时写入 A 和 D。可以指定 A、D 和 *A 的任意组合作为目标。
题目隐含的意思:
迷宫不会中途变更。
输出控制信号后,先得读取寄存器的值,判断是否已经执行完毕。
源码参考:
https://zhuanlan.zhihu.com/p/613188641
解题思路:一直直走,撞墙就左拐。
测试运行,检查结果是正确的。
界面说明:
Show Assembler Help 显示帮助信息
Reset state 可以重置程序
Check solution 检查结果,如果通过就是过关
computer区域,Tick按钮单步执行,Run直接跑,Reset重置机器状态。
最右边是robot的当前状态的文字显示,很像二十多年前的mud游戏。
跑完后的效果:
先简单注释下源码:
LOOP_FORWARD :
A = 0x7fff
D = *A
A = 0x0100 //判断bit8是否为1,前方是否有障碍。实际也判断了bit9、bit10是否为0
D = D - A
A = LOOP_TURN_LEFT
D; JEQ //撞墙了,调左转函数
A = LOOP_RE_READ
D; JGT //D大于0,说明bit9、bit10不为0,需要等待前面的动作执行完毕
A = 0x0004 //bit2设置为1,控制直走
D = A
A = 0x7fff
*A = D
A = LOOP_FORWARD
JMP
LOOP_TURN_LEFT : //左转函数
A = 0x0008 //bit3设置为1,控制左转
D = A
A = 0x7fff
*A = D
A = LOOP_FORWARD
JMP
LOOP_RE_READ : //重新探测robot状态
A = 0x7fff
D = *A
A = LOOP_FORWARD //寄存器为0时,控制直走
D; JEQ
A = 0x7fff
D = *A
A = 0x0100 //判断前方是否有障碍
D = D - A
A = LOOP_TURN_LEFT
D; JEQ //调左转
A = LOOP_RE_READ
JMP //接着等前面的执行完毕
有三个LOOP,可以理解为三个函数
A = LOOP_FORWARD
JMP
就是无条件调用LOOP_FORWARD函数
A = LOOP_TURN_LEFT
D; JEQ
是指D寄存器中的值==0时,调用LOOP_TURN_LEFT函数
A = LOOP_RE_READ
D; JGT
同理,D寄存器中的值>0时,调用LOOP_RE_READ函数
如果语法错误
会被标红,无法执行,例如:
鼠标放在标红的错误代码上时,会有错误提示信息弹出窗。