电玩圈游戏网 搜一搜

安卓手游去频道 >

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

安卓应用去频道 >

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

游戏视频去频道 >

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

资讯攻略去频道 >

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

专题合集去频道 >

游戏专题 应用专题

排行榜单去频道 >

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

首页>资讯>游戏攻略>深圳SHENZHENIO阿瓦隆城第4关电子射击练习靶攻略

深圳SHENZHENIO阿瓦隆城第4关电子射击练习靶攻略

作者:佚名来源:百度2022/06/29

深圳IO是一款硬核的编程游戏,有着严谨的游戏内容,那么一起来看看阿瓦隆城第4关电子射击练习靶的攻略吧。

关卡展示

现在有两名学员要练习射击。你现在要设计这么一个用来练习打靶的机器:

1,每一发的得分是根据命中位置和靶心间的直线距离决定的,(x0, y0) 和 (x1, y1) 间的距离的计算方法是初中知识,在座的各位应该都知道:根号[(y1 - y0)2 + (x1 - x0)2]。设命中位置和靶心的距离为 d,当 d < 10 时,得分 +4;当 10 ≤ d < 20 时,得分 +2;当 20 ≤ d < 30 时,得分 + 1;当 d ≥ 30 时,得分 -2。

2,初始状态下,打靶机上不显示任何数字。两名学员各发射 4 发子弹。从学员 1 发射第 1 发子弹开始,到学员 2 发射完第 4 发子弹为止,打靶机上要保持显示两名学员的实时分数。等 8 发子弹全部发射完毕后,显示器将最终得分闪烁 3 次后关闭。

3,本次的显示器和我们以往遇到的显示器不一样。以往的显示器只要发送一次数字就可以保持显示该数字,直到发送 -999 才关闭;这次的显示器如果你需要维持显示,那么必须不间断地发送数字。只要某一秒内你没有发送数字,显示器就会关闭。

又是一道分工合作的题。当然这次的分工合作比起第 1 关的“流水线”还是要复杂一点的。回顾一下第 1 关:总监把存/取的任务类型通过广播通知一下,然后将要存/取的食品编号告诉数据库管理员芯片,就去睡觉了;管理员修改了数据库以后,通知完了后面的工人芯片后,也去睡觉了。直到最后工人忙完,一项任务就自然完成了。整个流程就是从上到下一层一层传话,下级干完了自己的事情也不需要向上级汇报的那种。

但是本题里,存在一个“下级向上级反馈”的过程。我们的核心芯片在收到打靶信号后,需要委托下级 A 根据本次命中的位置计算得分。然后收到 A 的反馈后,将分差告知另外两个用于显示学员分数的下级,由它们来更新显示器上的数字。本题里,我们的核心芯片担任了“两头跑”的任务。因为它要两头跑,所以位置上放在中间是最合适的。我们先将本题的电路图搭出来。每块芯片我都用注释的方式解释了要完成什么任务。

我们先从两头跑的中央芯片开始写起。

本芯片的 acc 寄存器用来记录已经发出去的子弹数量。首先检查【检测】端口是不是激活状态(tcp p0 50)。当该端口为 100 时,说明有学员发射了 1 发子弹,令已发子弹数量 +1(+ add 1),然后将新的已发子弹数量同步到广播信号上去,供右侧的芯片反复使用(+ mov acc p1)。每击出 1 发子弹,我们都需要给左侧芯片发一个常数 50 唤醒它,委托它计算本回合的得分(+ mov 50 x1)。等待左侧芯片将本次射击的得分计算完毕后,我们接收从左侧芯片回传的得分数字,并发往右边的芯片,唤醒它们去更新显示器上的数字(+ mov x1 x3)。而如果本秒里【检测】端口的值为 0,说明没有学员发射子弹,本秒的学员得分自然就是 0,我们需要往右侧的芯片里发送 0。但我们要注意,题目要求打了第一枪以后显示屏才亮,所以仅当已发子弹数量不为 0 时,我们才能唤醒它们,请它们点亮显示屏(- teq acc 0, - mov 0 x3)。做完了两头跑的工作后,休眠一秒,进入下一个机器周期(slp 1)。此时,若前一秒钟发射了子弹,且发射的是第 8 发子弹(+ teq acc 8),则同时清空 acc 寄存器和广播信号,将已发弹药数清零,准备开启下一轮练习(+ mov p1 acc)。

为什么 teq acc 8 这条判断要加上 + 号呢?因为,当前一秒钟发射了第 8 发子弹时,这一秒钟就会立刻将已发子弹数清零。所以可以反推出,值为 8 的 acc 只能存活 1 秒钟,且存活的那 1 秒里,【检测】信号一定是 100。因此,根据【原命题和逆否命题等价】的原则,如果前一秒的【检测】信号是 0,那 acc 的值一定不是 8。所以我们将 teq acc 8 这条测试指令加上了 + 号,这样可以确保前一秒的【检测】信号为 0,+ 号指令未激活时,跳过这条必然不成立的判断,节省电量。

现在我们来写左边芯片的“计算得分”的代码。

两点间的直线距离涉及到根号运算,可假如我们真的去做根号运算的话,那就过于复杂了,而且也没有必要。因为我们关心的只是得分,而不关心得分是由【距离】还是【距离的平方】得来的。这里我们可以去掉开方的过程,改为将【距离的平方】和得分建立如下的映射关系:

当 d2 < 100 时,得分 +4;

当 100 ≤ d2 < 400 时,得分 +2;

当 400 ≤ d2 < 900 时,得分 +1;

当 d2 ≥ 900 时,得分 -2。

由于 MC 系列芯片在计算的过程中,出现上溢时会自动取 999,所以 d2 和得分的映射关系只和 d2 的百位相关。我们可以在计算完 d2 后取百位,然后通过 ROM 查表的方式来获得得分。我们的 ROM 里,0 ~ 9 的地址对应着不同的 d2 的百位,而每个格子表示【当前的 d2 百位所对应的得分】。当我们得到 d2 的百位,并将 ROM 的地址置为该数字后,读一次数据口,即得到了当前距离下的得分。

那么我们现在来看代码。根据题目提示,靶心的位置在 (50, 50)。那么我们只要计算 (y - 50)2 + (x - 50)2,即可得到 d2 的值。首先我们等待中央芯片的唤醒信号(slx x0)。唤醒后,我们首先计算 (y - 50)2 这部分的值(mov p0 acc, sub x0, mul acc),将该部分的值存入 dat 备用(mov acc dat)。注意以上的 -50 的部分(sub x0),必须使用 sub x0,不能使用 sub 50。因为我们必须将中央芯片发来的常数 50 给吸收掉,否则会导致运行时阻塞。接下来我们继续计算 (x - 50)2 这部分的值(mov p1 acc, sub 50, mul acc)。计算完毕后,加上原先存在 dat 里的 (y - 50)2,即得到了 d2 的值(add dat)。此时我们取出该值的百位数(dgt 2),将 ROM 地址置为该数字(mov acc x3),读取对应地址处的得分数字,并回传给中央芯片,即完成本次任务(mov x2 x0)。

最后是右边两块用于控制显示器数码管的芯片。代码如下:

这两块芯片的代码除了第 2~3 行的判断不一样以外,完全一致。首先都是等待中央芯片发来唤醒信号(slx x1)。中央芯片发送的是本秒内的射击得分。由于这个得分数字只发一次,所以两块芯片中有且只有一块芯片能接收这个得分数字。此时我们需要判断已发子弹数量是 ≤ 4 还是 > 4(tcp p0 5 / tcp p0 4)。当已发子弹数量 ≤ 4 时,正在行动的是 1 号学员,此时得分应该累加在 1 号学员身上,理应由管理 1 号学员的下方芯片接收这个分数值(- add x1);而当已发子弹数量 > 4 时,正在行动的是 2 号学员,此时得分应该累加在 2 号学员身上,理应由管理 2 号学员的上方芯片接收这个分数值(+ add x1)。

更新完了学员的得分后,两块芯片都将各自学员的实时得分发送到各自的输出端口(mov acc x2)。此时我们需要判断是否发完了所有 8 发子弹(+ teq p0 8)。如果没有发完,那就跳回到第 1 行,重新等待唤醒;当发完了 8 发子弹后,我们需要令显示器闪烁 3 次(共计 3 个 + slp 2 和 + mov acc x2),并将各自的得分清零,准备开启下一轮练习(+ sub acc)。

为什么这两块芯片里的 teq p0 8 这条判断也都加上了 + 号呢?因为当 p0 = 8 时,一定同时满足 p0 > 5(下方芯片 + 号)和 p0 > 4(上方芯片 + 号)的条件。根据【原命题和逆否命题等价】的原则,当 p0 满足 p0 ≤ 5 和 p0 ≤ 4 中的至少一个条件时,p0 一定不等于 8。所以只有在 + 号指令激活的时候,执行这条判断才有意义。+ 号指令未激活时,我们完全可以跳过这条必然不成立的判断,节省电量。

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

评论 (0)

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

上拉或点击查看更多