电玩圈游戏网 搜一搜

安卓手游去频道 >

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

安卓应用去频道 >

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

游戏视频去频道 >

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

资讯攻略去频道 >

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

专题合集去频道 >

游戏专题 应用专题

排行榜单去频道 >

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

首页>资讯>游戏攻略>深圳SHENZHENIO阿瓦隆城第10关神经处理逻辑主板攻略

深圳SHENZHENIO阿瓦隆城第10关神经处理逻辑主板攻略

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

深圳IO是一款硬核的编程游戏,有着严谨的游戏内容,那么一起来看看阿瓦隆城第10关神经处理逻辑主板的攻略吧。

关卡展示

出现了,长度 25 的数据包,所有关卡里最长的,没有之一。

本关里,我们的线路板上已经固定好了两个神经处理单元:LOGOS 和 TELOS。这两个元件占用空间极大,且已被焊死在电路板上,不能移动,非常坑。

这两个元件左侧的 x 口会不定期地发送一些长度为 25 的数据包,设这些数字为 a~y。仅当收到的数据包满足 a - b + c - d + e - ... - x + y = 0 时,才向【网眼数据】端口发送收到的数据包。否则视为数据包已损坏,直接丢弃。

与此同时,我们需要每隔 5 秒给 LOGOS 和 TELOS 右侧的泵端口发送一次心跳信号。特殊地,当输入端生成了新的数据包时,立刻启动心跳,并重置计时器。

本关需要 5 块芯片和 2 块 RAM 在一起分工合作,且需要用到一个我雪藏至今,终于不得不点破的隐藏特性。电路图如下所示:

放置在 LOGOS 左右两侧的芯片分别用于接收 LOGOS 的数据包及控制 LOGOS 的心跳,分别为 1、2 号芯片;放置在 TELOS 左右两侧的芯片分别用于接收 TELOS 的数据包及控制 TELOS 的心跳,分别为 3、4 号芯片;最左侧的芯片连接着用于存储数据包的两块 RAM 以及【网眼输出】的最终输出口,为 5 号芯片。

你可能会觉得 1、2 号芯片的连线有点奇怪。1 号芯片的 x0 口,以及 2 号芯片的 x1 口,各有一截导线露在外面,但看上去又没跟任何端口相接。与此同时,LOGOS 和 TELOS 中间的那一条导线是从哪来的,找不到源头呀?

其实,这个游戏的导线,不仅可以放置在线路板的空白位置,还可以放在芯片的背面。当线路板的空间捉襟见肘时,我们仍然可以利用元件背面的可用空间,来连接导线。我们按住 TAB 键,可以看到电路板的透 视图:

破案了。1 号芯片的 x0 口,以及 3 号芯片的 x1 口的导线的电流汇集到了 LOGOS 和 TELOS 中间的那一条路上,之后又分流到了右侧控制各自心跳的 2、4 号芯片上。这种从元件背面穿过的导线(简称【背线】,下同)有两种画法:一是按住 TAB 键后画,二是先把导线画好,再拖动元件到对应的位置,让元件“覆盖到导线上面”。

以前的关卡,电路板的可用面积都十分充足,因此我一直没有提到【背线】这样的隐藏特性。但是这一关,因为两块巨大的神经处理单元占用掉了相当多的线路板面积,且无法移动,已经属于是不走背线就没地方放置导线了。我不得已才点破了这个一直以来都被雪藏了的特性。

唉,明明电路板右边还有那么多的空白。但凡这两个大东西可以向右挪一格,我都不至于要这么尴尬地走背线。

本关的 LOGOS 和 TELOS 仅仅是名字不一样,功能上是完全一样的。为了降低问题复杂度,我们先考虑只监视其中一块主板,无视另一块。观察时序图发现,第一个样例里,【网眼输出】端口打印出的都是 TELOS 的数据包。如果我们先实现 LOGOS 的部分,那即使实现了也无法打印出任何数据包,也就无法验证算法的正确性。所以这里我们先实现 TELOS 的部分。我们先写出和 TELOS 直接相连的 3、4 号芯片的代码:

3 号芯片每秒钟都将 TELOS 中的首数字发给 4 号芯片,由它判断是否需要开启 TELOS 的心跳并重置计时器(mov x3 dat, mov dat x1)。之后检查首数字是否为 -999(tcp dat -999)。首数字是 -999 时,说明本秒没有数据包,也就不需要计算校验码,更不需要向左侧的 5 号芯片发送数据,此时直接关闭所有 + - 号指令跳到最后睡觉即可(slp 1)。首数字不为 -999 时,说明本秒钟里会从 TELOS 收到一个长度为 25 的数据包。我们将首数字发给左侧的 5 号芯片后(+ mov dat x0),接下来的第 5、6、7、8、9、4 行代码构成了一个“先判断,后执行”的循环:若前一个读入的数字不为 -999(+ tgt dat -999),我们就将 acc 取反(+ mul -1)并加上这个数字(+ add dat)。做完这些后再从 TELOS 读入下一个数字发出去(+ mov x3 dat, + jmp 4),如此循环,直到读入的数字为 -999 为止。读到 -999 后,将计算好的校验码发给 5 号芯片(- mov acc x0),并在发送完毕后,清除残留在 acc 里的校验码数据,准备迎接下一次任务(- sub acc)。至此,本秒的任务就完成了,可以安心睡觉了(slp 1)。

也就是说,没有从 x 口接收到数据包时(首数字是 -999),则只给 4 号芯片发信号,不给 5 号芯片发信号;一旦从 x 口接收到了数据包(首数字不是 -999),则除了要将首数字发给 4 号芯片外,还要不断从 TELOS 中读取数字发给 5 号芯片,把整个数据包都发给 5 号芯片,直到读完数据包内所有的数字,接收到 -999 为止。同时,因为循环结束的条件是【前一个接收到的数字是 -999】,所以刚接收到最后的 -999 时,也要将这个 -999 发送给 5 号芯片。这是为了给 5 号芯片发送一个结束信号。5 号芯片因为端口数量有限,只连接了 RAM 的数据口,没有连接地址口,它自己无法方便地判定还剩余多少个数字要接收。这一点我们在说到 5 号芯片时也会去详细解释。

我们在接收数据包的过程中,是这样迭代计算校验码的:

若前一个读入的数字不为 -999(+ tgt dat -999),我们就将 acc 取反(+ mul -1)并加上这个数字(+ add dat)。

每读入一个数字就将 acc 取反后再加上这个数字。而题目要求用第一个数 减去 第二个数 加上 第三个数 减去 第四个数 加上 第五个数……这样的方式来计算校验码。这里,我这样简单迭代了一下,就规避掉了原始的“加减号反复横跳”的运算。这是为什么呢?我们来分析一下:

当收到第一个数 a 时,acc 的值变成了:0 × (-1) + a = a;

当收到第二个数 b 时,acc 的值变成了:a × (-1) + b = -a + b;

当收到第三个数 c 时,acc 的值变成了:(-a + b) × (-1) + c = a - b + c;

当收到第四个数 d 时,acc 的值变成了:(a - b + c) × (-1) + d = -a + b - c + d;

当收到第五个数 e 时,acc 的值变成了:(-a + b - c + d) × (-1) + e = a - b + c - d + e;

……

当迭代到第奇数项时,所有奇数项前都是 + 号,所有偶数项前都是 - 号;当迭代到第偶数项时,所有奇数项前都是 - 号,所有偶数项前都是 + 号。因此,如果数据包的长度是偶数,那么迭代后需要整体乘以 -1,将符号翻转成“奇数项前是 + 号,偶数项前是 - 号”才能得到正确的校验码;而如果数据包的长度是奇数!迭代后就会直接满足“奇数项前是 + 号,偶数项前是 - 号”这样的条件,此时不用做任何处理,直接得到的就是最终的校验码!本题中,数据包的长度是 25,是奇数。因此只要按照这样的方法迭代,就能得到正确的校验码。

然后是控制 TELOS 心跳的 4 号芯片。当 3 号芯片发来的数字不是 -999 时(tgt x1 -999),立刻产生心跳信号(+ mov 100 p0, slp 1),1 秒后同时重置心跳信号和计时器(+ mov p0 acc)。而当 1 号芯片发来的首数字是 -999 时,需要判定 acc 是否到达了 4,即前一秒是不是计时器重置以来的第 4 秒(- teq acc 4)。前一秒尚未到达第 4 秒时,令计时器 +1(- add 1);若前一秒到达了第 4 秒,则本秒是第 5 秒,同样产生心跳信号(+ mov 100 p0, slp 1),同样在 1 秒钟后重置心跳和计时器(+ mov p0 acc)。

最后的麻烦来了,长度为 25 的数据包,怎么存储,并在校验正确的情况下读取并发送呢?请看和【网眼数据】端口通信的 5 号芯片的代码:

每个数据包有 25 个数字,需要两块 RAM 才能存得下。这里,同时操作两块 RAM 的话,就只能连接数据口,而不能连接地址口了,如图所示。不过,在这一关里,我们即使不连接地址口,也是可以完成任务的。

首先我们等待 3 号芯片的唤醒信号(slx x2)。3 号芯片一共会向本芯片发送(包括 -999 结束标志在内的)26 个数字,我们将第奇数个数字放在下方的 RAM 里(mov x2 x1),而将第偶数个数字放在上方的 RAM 里(mov x2 acc, mov acc x3)。每接收到一次第偶数个数字,就判断刚才接收的数字是否是 -999(teq acc -999)。如果接收到的不是 -999,就说明仍有待接收的数字,此时关闭所有的 + 号指令,跳回第 1 行继续接收,如此循环,直到接收到 -999 为止。接收到 -999 后,3 号芯片还会把校验码也发过来,我们检查校验码是否为 0(+ teq x2 0)。当校验码不为 0 时,说明我们收到了受损的数据包,直接什么都不做,关闭所有的 + 号指令,跳回第 1 行等待下一个数据包。而如果校验码为 0,说明收到的数据包是有效的,我们需要将这个数据包从 RAM 中重新读出来,并发给【网眼数据】端口。

因为一共接收了(包括 -999 结束标志在内的)26 个数字,所以读取之前,我们的两块 RAM 的地址指针都偏移到了原始地址 +13 的位置。这时候,我们需要同时让两块 RAM 的地址都增加 1,这样即可让 RAM 指针偏移到相对原始地址 +14 的位置,即回到原位。这里,我们在一条指令里读一个 RAM 的值,并写给另一个 RAM,令两块 RAM 的指针都 +1(+ mov x1 x3)。发送数据包时,我们先从下方的 RAM 里读取第奇数个数字直接发送(+ mov x1 x0),再从上方的 RAM 里读取第偶数个数字暂存(+ mov x3 acc)。读到第偶数个数字时,需要先判断是否读取到了结束标志 -999(+ tcp acc -999)。如果尚未读到结束标志,则说明读到的是一个有效的“第偶数位数字”,将它发送给输出端口后(+ mov acc x0),跳回到第 8 行继续读取下一组数字(+ jmp 8)。如此循环,直到读到 -999 为止,当前数据包就发送完毕了,跳回到第 1 行等待下一次任务即可。

点击左下角的【模拟】,观察时序图:

发现【网眼输出】和【TELOS 泵】的输出都正确了。【LOGOS 泵】因为还没有写入控制代码,所以暂时没有输出信号。

现在我们要给 1、2 号芯片写上代码,让 LOGOS 跑起来。1、2 号芯片的代码和 3、4 号芯片的代码非常相似,仅仅做了点微调。如下:

1 号芯片在 3 号芯片代码的基础上做了两处修改:①1 号芯片改为 x0 口和右边连接,x1 口和左边连接,和 3 号芯片正好反过来,因此代码里的 x0、x1 做了互换;②第 2、3 行代码的顺序做了调整。3 号芯片中是先发心跳信号再判断首数字是不是 -999,而 1 号芯片是先判断首数字是不是 -999,激活 + - 号后再发心跳信号。

2 号芯片则是在 4 号芯片代码的基础上,于开头加了一句等待唤醒指令(slx x1)。至于 + 号部分的代码,为什么改为使用 gen 指令(+ gen p0 1 0, + sub acc),纯粹是为了跟 4 号芯片保持同样的 6 行代码。我这里选择的是代码行数一致的方案,如果你选择多一行,但代码风格一致的方案(+ mov 100 p0, slp 1, + mov p0 acc)也是可以的。

以上的改动都是为了时序同步上的需要。LOGOS 和 TELOS 两块巨大的神经处理单元中间只有短短的一行空白可以让导线经过,右边的两块芯片都通过这同一根导线接收数据,因此时序上的同步很重要。如果两块芯片互相接收到了原本是发给对方的数据,就会导致心跳信号的混乱。

3 号芯片先发送首数字,再判断它是不是 -999;1 号芯片先判断首数字是不是 -999,激活 + - 号后再发送它。中间狭窄通路上的导线,每秒钟都会有两个数字在跑。我们经过以上同步处理后,可以确保在这条狭窄的通路上,TELOS 的数字一定在前,LOGOS 的数字一定在后。右侧的 4 号、2 号芯片则是:数据还在狭窄通路上行进的时候,4 号芯片就已经迫不及待了(tgt x1 -999),而 2 号芯片还在呼呼大睡(slx x1);数据到达后,4 号芯片“快人一步”将第一个数字拿走的时候,2 号芯片才刚醒,等到撑完懒腰以后,就只能拿走第二个数字了。

我们这样微调了一下时序以后,就可以确保数据的发送和接收都处于有序状态,这样右侧的两块芯片收到的都是自己所需要的数字,不会产生混乱。

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

各位,别急着走,这还不是最终 BOSS 关,最终 BOSS 关是编号为 3113 的隐藏关第 3 关。最终 BOSS 关就算世界纪录,电量也超过了 5K,可想而知复杂度有多高。

评论 (0)

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

上拉或点击查看更多