电玩圈游戏网 搜一搜

安卓手游去频道 >

角色扮演 射击枪战 棋牌卡牌 体育运动 角色扮演 赛车竞速 休闲益智 音乐舞蹈 模拟经营 战棋塔防 推理解谜 策略战争

安卓应用去频道 >

社交通讯 系统工具 影音视听 拍摄美化 效率办公 学习教育 生活服务 旅游出行 资讯阅读 金融理财 网络购物 游戏助手

游戏视频去频道 >

动作冒险 射击枪战 棋牌卡牌 体育运动 角色扮演 赛车竞速 音乐舞蹈 模拟经营 战棋塔防 推理解谜 策略战争 休闲益智

资讯攻略去频道 >

手游资讯 手游攻略 手游问答 游戏资讯 游戏杂谈 游戏攻略 软件教程 软件资讯

专题合集去频道 >

游戏专题 应用专题

排行榜单去频道 >

游戏排行 应用排行
首页 游戏 应用 视频 资讯 专题 榜单

首页>资讯>游戏攻略>深圳SHENZHENIO阿瓦隆城第8关脑机接口攻略

深圳SHENZHENIO阿瓦隆城第8关脑机接口攻略

作者:佚名来源:百度2022/07/11

深圳IO是一款硬核的编程游戏,有着严谨的游戏内容,那么一起来看看阿瓦隆城第8关脑机接口的攻略吧。

关卡展示

从本关开始,BGM 都变得深沉了。我原以为进了阿瓦隆城就是地狱了,没想到前面的关卡还都是练手的,从这关开始才是地狱。

本关的要求很简单:一共有 6 路传感器输入。当最近的 2 秒内检测到至少两路有脉冲信号时,向输出端口报告近 2 秒内哪些端口产生了脉冲信号。要求按照数字大小顺序报告,不能乱序报告。报告完毕后的下一秒里不会有任何传感器发生脉冲信号,请确保相邻的数据包间至少有 1 秒的间隔,不要重复报告上一秒的脉冲。

其实总共只有两种情况需要报告:

同一秒内有两路以上的输入信号产生了脉冲。例如:第 1 秒里,传感器 1~3 同时变为 100,传感器 4~6 保持为 0。此时向输出端口发送【1、2、3】的数据包。

前一秒里有且仅有一路输入信号产生了脉冲,紧接着的后一秒里有至少一路输入信号产生了脉冲。例如:第 1 秒里,传感器 1 变为 100;第 2 秒里,传感器 2、3 变为 100。此时需要在第 2 秒时向输出端口发送【1、2、3】的数据包。

其余的情况,都不需要报告。如果在上面的例子里,传感器 2、3 改为在第 3 秒时才变为 100,那么在第 2 秒时,传感器 1 会回归为“未产生脉冲信号”的状态,第 3 秒时我们只需要向输出端口发送【2、3】的数据包。

本题需要 4 块芯片分工合作完成任务。1 号芯片“两头跑”,先从输入端获取两块 DX-300 转接后的三位数,然后呼叫 2 号芯片,令它计算两秒内有多少路输入产生了脉冲信号。得到 2 号芯片的反馈后,判断产生了脉冲信号的路数是否 > 1。满足条件时,将两个三位数发给 3 号芯片,然后由 3、4 号芯片共同将数据包发给输出端口。电路图和代码如下:

6 路输入,首先肯定是二话不说,两块 DX-300 安排上。最左边的 MC6000 和两块 DX-300 直接连通,因此它是 1 号芯片。它的 x3 口连接着中央的 2 号芯片,x2 口连接着底部居中的 3 号芯片。

我们先来看“两头跑”的 1 号芯片的代码:

首先把两路 DX-300 提供的三位数都发给 2 号芯片,委托它计算近两秒内有多少路输入产生了脉冲信号(mov x0 x3, mov x1 x3)。2 号芯片在计算完毕后,会返回一个值,这个值的含义就是【近 2 秒内产生了脉冲的路数】。当近 2 秒内没有发生脉冲,或有且仅有一路发生了脉冲时(tgt x3 1),仅仅将这两个三位数暂存到 acc 和 dat 里,不通知 3 号芯片发送数据包(- mov x0 acc, - mov x1 dat)。而当路数 > 1 时,我们要将近 2 秒内发生过脉冲的所有传感器都告知第 3 块芯片,由它向输出端口发送数据包。

问题来了:你怎么将当前这 1 秒的三位数和存在 acc/dat 里的前 1 秒的三位数合并,转换为近 2 秒内的三位数?

答案是使用加法。我们就以前三路输出为例:第一秒钟传感器 0 发生了脉冲信号,x0 读到了 001;第二秒钟传感器 1、2 发生了脉冲信号,x0 读到了 110。由于第一秒钟只有一路信号产生了脉冲,因此在上一秒里,我们将 001 这个值存入了 acc。那么,到了这一秒时,我们将上一秒的 acc 加上本秒的 x0,001 + 110 = 111,就得到了“传感器 0~2 在近 2 秒内都产生了脉冲信号”的三位数。后三路输入也是同理。

我们的代码也正是使用加法来计算哪些输入在近 2 秒内产生了脉冲信号的。首先,令 acc 加上 x0,将近 2 秒内【前三个传感器】的脉冲状态合并后(+ add x0)发给 3 号芯片,通知 3 号芯片发送数据包的前半部分(+ mov acc x2)。然后再令 dat 加上 x1,将近 2 秒内【后三个传感器】的脉冲状态合并后(+ mov dat acc, + add x1)发给 3 号芯片,通知 3 号芯片发送数据包的后半部分(+ mov acc x2)。做完这些后,休眠一秒,进入下一个时钟周期(slp 1)。

然后来看用于计算【近 2 秒内产生了脉冲的路数】的 2 号芯片的代码:

首先我来解释一下右边的 ROM 是干什么用的。这是一个用来计算【三位数里有多少个 1】的 ROM。我们将 ROM 的地址值置为八种 DX-300 三位数中的一种时,其指向的数字正好等于【这个三位数中 1 的个数】。

向地址口传入 000 时,0 mod 14 = 0,地址指针会指向 0 号空间。0 号空间里的值是 0,代表 000 中有 0 个 1;

向地址口传入 001 时,1 mod 14 = 1,地址指针会指向 1 号空间。1 号空间里的值是 1,代表 001 中有 1 个 1;

向地址口传入 010 时,10 mod 14 = 10,地址指针会指向 10 号空间。10 号空间里的值是 1,代表 010 中有 1 个 1;

向地址口传入 011 时,11 mod 14 = 11,地址指针会指向 11 号空间。11 号空间里的值是 2,代表 011 中有 2 个 1;

向地址口传入 100 时,100 mod 14 = 2,地址指针会指向 2 号空间。2 号空间里的值是 1,代表 100 中有 1 个 1;

向地址口传入 101 时,101 mod 14 = 3,地址指针会指向 3 号空间。3 号空间里的值是 2,代表 101 中有 2 个 1;

向地址口传入 110 时,110 mod 14 = 12,地址指针会指向 12 号空间。12 号空间里的值是 2,代表 110 中有 2 个 1;

向地址口传入 111 时,111 mod 14 = 13,地址指针会指向 13 号空间。13 号空间里的值是 3,代表 111 中有 3 个 1。

解释完了这个 ROM 的作用,我们来看 2 号芯片的代码。本芯片中的 acc 寄存器用于记录前一秒里产生了脉冲信号的路数。首先我们接收 1 号芯片发来的第一个三位数,将其置为 ROM 的地址(mov x1 x3),然后读一格 ROM,获得前三位数里 1 的个数。此时我们需要判断前一秒里是不是有且仅有一路脉冲信号(teq acc 1)。如果前一秒里有且仅有一路脉冲信号,那么需要将前一秒的脉冲信号顺延到这一秒。我们从 ROM 中读取到前三位数里的 1 的个数后,要将这么多 1 和前一秒的那一个 1 做累加运算(+ add x2)。其余情况,前一秒的脉冲都不顺延到这一秒,都是直接覆盖,不做累加运算(- mov x2 acc)。做完以上操作后,我们再接收 1 号芯片发来的第二个三位数,将其置为 ROM 的地址(mov x1 x3),然后读一格 ROM,获得后三位数里 1 的个数。将其累加到 acc 上(add x2)。如此,便得到了【近 2 秒内产生了脉冲的路数】。我们将这个值回传给 1 号芯片(mov acc x1)。

此时要注意,如果前一秒有且仅有一路脉冲信号(即 teq acc 1 成立),那么到了此处,我们必须要强制将 acc 清零(+ sub acc)。原因如下:

如果本秒内没有出现脉冲信号,acc 的值会保持为 1。但是我们最多只能将孤立的脉冲信号向后顺延 1 秒,不能向后顺延更长时间。1 秒过后,如果这个孤立的脉冲信号没有被接收,那就只能被消灭。强制将 acc 清零,不让这个孤立的脉冲信号向后顺延更久。

如果本秒内出现了其他的至少一路脉冲信号,acc 的值会变成 2 以上。此时清零与否效果一致,但为了节省一行判断,上一秒的 acc 是 1 时,这一秒就统一清零了。

做完这些后,睡眠,等待下一次被 1 号芯片唤醒(slx x1)。

最后是下方用于传输数据的 3 号、4 号芯片:

3 号芯片在收到由 1 号芯片发来的三位数后(slx x0, mov x0 dat),依次提取出这个三位数的个位(dst 0 dat, mov acc x3)、十位(mov dat acc, dgt 1, mov acc x3)和百位数,发给 4 号芯片(mov dat acc, dgt 2, mov acc x3)。1 号芯片每次呼叫 3 号芯片,都会发两个三位数,3 号芯片也相应地重复做两次这样的事。

4 号芯片的 acc 用来记录当前接收到的是第几位数字。6 位数字里,每出现一个 1,就表示当前位数所指示的传感器发生了脉冲信号,我们就需要将对应的编号发送给输出端口。每当收到一位数字时(slx x0),检查这位数字是否大于 0(tcp x0 0)。大于 0 时,将 acc 表示的位数(即传感器编号)发送给输出端口(+ mov acc x1)。然后检查刚才接收的是不是第 5 位数字(teq acc 5)。尚未接收到第 5 位数字时,说明还有等待接收的数字,令位数 +1(- add 1)并跳回第一行继续接收,直到接收完第 5 位数字为止,将位数归零(+ sub acc),准备迎接下一次任务。

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

优化电量

题目已经保证了报告后的下一秒一定不会有脉冲信号。所以报告完毕后的那一秒,我们可以手动将 1 号芯片的 acc 和 dat 的值置零,无需调用 2 号芯片计算后归零。我们将 1 号芯片的代码改成如下的样子:

我将改动过的地方加上了注释。

当近 2 秒内没有发生脉冲,或有且仅有一路发生了脉冲时(tgt x3 1),仅仅将这两个三位数暂存到 acc 和 dat 里,不通知 3 号芯片发送数据包(- mov x0 acc, - mov x1 dat)。做完这些后,只休眠 1 秒,下一秒里继续判定是否有其他路的脉冲信号(- slp 1)。

而当路数 > 1 时,首先,令 acc 加上 x0,将近 2 秒内【前三个传感器】的脉冲状态合并后(+ add x0)发给 3 号芯片,通知 3 号芯片发送数据包的前半部分(+ mov acc x2)。然后再令 dat 加上 x1,将近 2 秒内【后三个传感器】的脉冲状态合并后(+ mov dat acc, + add x1)发给 3 号芯片,通知 3 号芯片发送数据包的后半部分(+ mov acc x2)。做完这些后,我们手动将 acc 和 dat 的值清零(+ mov 0 acc, + mov 0 dat),然后休眠 2 秒,跳过下一秒的脉冲检测过程(+ slp 2)。

另外,我在龙腾第 16 关《幽灵娃娃》的攻略里说过:

播放特定音效时,我们需要读取连续的 14 个波形数据。14 除自己外的因数有 1、2、7,也就是说,我们在循环的过程中,每次循环读取 1/2/7 个波形数据时,都能保证循环正常结束。

到这一关里,每次发送数据包时,都需要检查 6 位数是否为 1。6 除自己外的因数有 1、2、3,因此我们在循环检查的过程中,每次检查 1/2/3 位数,都能保证循环正常结束。用于发送数据的 4 号芯片还有 3 行代码空间,我们完全可以一次检查 2 位数,减少循环结束的判断次数。

选中的部分是我们增加的代码。由于 3 也是 6 的因数,我们甚至还可以一步到位,将这块 MC4000 换成 MC6000,一次检查 3 位数字,进一步节省电量:

当然,换成 MC6000 以后,端口的名称也相应地发生了变化,代码中的端口名也要相应地做修改(x1→x2, x0→x1)。

嗯……再进一步,总共就 6 次判断,有必要循环吗,有必要用 acc 吗?直接暴 力大法就好:

我们加了 2 块钱,多写了 10 行代码,让电量从 1.8K 降到了 1.2K。效率提升了 1/3。

评论 (0)

相关阅读
网友评论0条评论

上拉或点击查看更多