欢迎光临散文网 会员登陆 & 注册

【深圳 IO 攻略】第 31 关:安全网追踪徽章

2022-06-15 16:58 作者:ココアお姉ちゃん  | 我要投稿

本文首发于 B 站《深圳 IO》文集(https://www.bilibili.com/read/readlist/rl569860)。原创不易,转载请注明出处。

关卡展示

这一关我们需要结合数据手册来分析

我们首先看【同步雷达】信号,【同步雷达】的值是用于指示雷达当前所在方位的。我们视正北方向为 0°,则【同步雷达】的值和方位角度呈如下对应关系:0 = -30°~30°,20 = 30°~90°,40 = 90° ~ 150°,60 = 150° ~ -150°, 80 = -150° ~ -90°,100 = -90° ~ -30°。时序图里,【同步雷达】信号永远按照 0→20→40→60→80→100→0…… 的方式循环,说明雷达在不断按逆时针方向旋转。

再看【脉冲雷达】信号。当雷达未朝向用户时,该信号会保持为 0;而当雷达正面朝向用户时,该信号的值会在瞬间变为“距离用户的直线距离”。

最后,无线 rx 会不定期地发送一些数据包。当你收到了 1 开头的数据包时,说明这是一个声音波形的数据包。这个数据包的第二个数字表示波形长度,后续的数字数量等同于该长度。你需要将这些波形原封不动地输出到【扬声器】中。当你收到了 2 开头的数据包,且第二个数字和锁中的数字一致时,我们需要根据雷达的方向、雷达和用户的直线距离这两个数据,计算用户当前所在的区域,并将对应的区域代码发送给【无线 tx】。例如,方位为 60,距离为 50 时,说明用户在工业区,需要发送 700。

这一关仍然是分工合作,一块芯片用于随时确定用户的位置,另一块芯片用于接收并处理无线 rx 发来的数据包。

两块写得满满的芯片。我们先来分析左边的芯片,左边的芯片要完成的任务是:当右边的芯片发来请求信号时,左边的芯片通过雷达的方向,以及和用户的直线距离这两个数据,计算用户所在区域,并将区域代码回传给右边的芯片。

首先我们等待右边的芯片发来信号(slx x3)。右边芯片发来的一定是非 0 的【脉冲雷达】信号的值(也就是和实时的 p0 值相等),第一句 tcp x3 79 和 tcp p0 79 完全等价,这里使用 x3 而不使用 p0 的原因是为了释放掉从右边芯片发来的数据,防止阻塞。

首先我们检查距离值是否 ≥80(tcp x3 79)。根据地图上的指示,一旦距离 ≥80 时,用户不论处于什么方位,都一定位于政府大楼。所以满足以上条件时,直接回传政府大楼的区域编号 100(+ mov 100 x3),同时跳回第一行,不再执行下方的一切代码(+ jmp 1)。

然后再检查方位值是否在 -30°~30° 范围内(teq p1 0)。根据地图指示,方位为 0 且距离小于 80 时,用户一定位于港口。而执行到此处时,距离一定是小于 80 的。所以执行到此处时,只需要方位为 0 就可判定用户位于港口,直接回传港口的区域编号 600 即可(+ mov 600 x3),同时跳回第一行,不再执行下方的一切代码(+ jmp 1)。

接下来,继续判断距离值是否 ≤50(tlt p0 51)。根据地图指示,距离在 0~50 范围内,且方位不在 -30°~30° 范围内时,用户一定位于工业区。执行到此处时,第二个条件一定是成立的,所以只要距离 ≤50,就直接回传工业区的区域编号 700 即可(+ mov 700 x3)。而当距离在 50~80 范围内时,回传的区域编号和方位值有关:方位值为 20 时,区域编号为 200;方位值为 40 时,区域编号为 201……方位值为 100 时,区域编号为 204。我们发现距离 50~80 且方位值不为 0 时,区域编号和方位值满足如下函数关系:

除以 20 相当于乘以 5 再除以 100,相当于乘以 5 后取百位。因此,当距离 50~80 且方位值不为 0 时,我们将方位值放入 acc(- mov p1 acc),将它乘以 5(- mul 5),取得百位数字(- dgt 2),再加上 199(- add 199)即得到了对应的区域编号,将该编号回传给右边的芯片,即完成任务(- mov acc x3)。

然后我们看右边的芯片。右边芯片有两个任务:一个是在收到【脉冲雷达】信号时,委托左边的芯片计算用户所在的区域;另一个是收到无线 rx 的数据包时做出相应处理。

首先我们检查是否出现了【脉冲雷达】信号(tcp p0 0),一旦出现,将当前的信号值发给左边,唤醒左边的芯片(+ mov p0 x0),等待它将用户所在的区域编号计算好后,将该编号存入 dat 寄存器(+ mov x0 dat)。

第 4~7 行用于检查是否仍有尚未播放完的音频数据,我们暂时跳过去,先从第 8 行开始看。当没有音频数据时,我们需要将扬声器置为静音(mov 50 p1)。然后我们读取数据包。当数据包的首数字是 1 时(teq x2 1),我们将第二个表示长度的数字读入 acc(+ mov x2 acc),然后跳回到第 5 行开始播放音效(+ jmp 5)。现在跳回第 5 行,我们播放一格声音波形(+ mov x2 p1),令音频剩余长度 -1(+ sub 1),然后跳到最后休眠一秒(+ jmp e, slp 1)。后面的时间里,只要声音没有播放完,我们的程序就一边检测用户位置有没有改变(1~3 行),一边播放剩下的声音(4~7 行及 14 行),直到声音播放完毕后,将扬声器静音(第 8 行)。

现在看第 12 行。无论是无线 rx 队列里没有数字,读到了 -999,还是数据包的首数字不是 1,我们都尝试去读入第二个数字,检查它和锁中的数字是否相等(teq x2 x1)。如果数据包中没有数字时,读到的一定还是 -999,和锁中的数字一定不一致(这是游戏里的设定),直接什么都不做,跳到最后休眠(slp 1)。仅当第二个数字和锁中的数字一致时,我们先将用户当前所在的区域编号发送给 tx(+ mov dat x3),然后再休眠(slp 1)。

点击左下角的【模拟】,稍等片刻,便会弹出结算界面:

这一关需要特别注意这样一个小细节:播放音频的过程中仍然需要不断探测用户的位置改变了没有。我们上面的代码里的 4~7 行将播放音频的过程从循环中分离了出来,变成了每个时钟周期的例行公事。每个时钟周期里,右边的芯片要做两件例行公事:①检查是否出现了【脉冲雷达】信号,一旦出现就要通知左边的芯片计算用户所在区域。②检查是否仍有没播放完的音频,若仍有,则从无线 rx 中读取波形信号发送到扬声器。

如果我们还按常规思路,将播放音频的过程写在循环里,每播放一格就睡一秒,令 acc -1,直到 acc 减为 0 之前一直循环读取,把代码写成类似下面这个样子的话:

第 4~10 行是用传统思维实现的【播放声音波形】任务

那么就会造成一个问题:播放声音的过程中,芯片不再检测外部是否产生了【脉冲雷达】信号,不再更新用户所在的区域位置。最终运行时会卡在这么一个样例上:

这个错误就是典型的“播放声音的过程中,用户的位置都变了,你却只顾着播放声音了,忘了去更新用户的位置”。

至此,恭喜你完成【深圳龙腾有限公司】系列的所有关卡。请准备前往【阿瓦隆城】,开启 hard 模式,接受更大的挑战!

【深圳 IO 攻略】第 31 关:安全网追踪徽章的评论 (共 条)

分享到微博请遵守国家法律