电玩圈游戏网 搜一搜

安卓手游去频道 >

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

安卓应用去频道 >

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

游戏视频去频道 >

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

资讯攻略去频道 >

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

专题合集去频道 >

游戏专题 应用专题

排行榜单去频道 >

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

首页>资讯>游戏攻略>深圳SHENZHENIO第15关卡宾枪瞄准照明器攻略

深圳SHENZHENIO第15关卡宾枪瞄准照明器攻略

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

深圳IO是一款硬核的编程游戏,有着严谨的游戏内容,那么一起来看看第15关的卡宾枪瞄准照明器的攻略吧。

主界面

由于游戏过分硬核,先放个手册中的图看看冰山一角:

不过这也正对应了嵌入式开发中会遇到的海量数据手册,相当程度上还原了嵌入式日常开发的情景。

游戏中设计到部分的编程有些类似于汇编语言,这里上手还是有一些些难度的,大家请做好准备,继续直接扔核弹:

不用害怕,在游戏过程中,会逐步引导你学会使用新的指令,对于新的器件,也是随着主线的进行逐步开放的

在游戏中,你不仅可以完成指定的基本目标,还可以挑战全网玩家,看谁能达成最佳优化目标。

鱼和熊掌不可兼得,多数情况下想要达成更好的性能就要增加成本啦,不过这正是优秀的嵌入式开发人员的意义所在——比你好,还比你的便宜。

第 15 关:卡宾枪瞄准照明器

关卡展示

这一关我们需要在【雷达输出】信号出现时开始计时,【雷达输入】信号出现时停止计时,然后根据计时时长给【激光】、【泛光 20】和【泛光 60】三个输出口输出对应的映射值。映射关系需要参考数据手册:

首先我们肯定是计算【雷达输入】和【雷达输出】信号的差值。若为负数,说明【雷达输出】信号激活,开始计时。若为正数,说明【雷达输入】信号激活,停止计时,同时根据计时值向右边的三个输出口写入映射值。平时没有【雷达输出】和【雷达输入】信号时,正常计时。

左边的芯片用来计时。首先不断监测输入和输出的差值(tcp p0 p1),当输出信号出现时(差值为负数)清除 acc(-mov 0 acc);当输入信号出现时(差值为正数)将经过的秒数传给右边的芯片(+ mov acc x1),由右边的芯片控制激光和泛光。做完这些事后睡一秒。当然,如果没有检测到差分信号,那就什么都不用做,直接睡觉(slp 1)。睡完一秒后,令经过的秒数 +1(add 1)。

然后我们看右边的芯片。首先等待左边的芯片传入信号(slx x0),然后因为秒数在后面需要读两次,所以需要放入 acc 寄存器暂存。(mov x0 acc)。后续的判断又是一个典型的三态判断。这里我们把六种状态压缩成了三种,先默认向激光和泛光端口写中间状态的值,然后用 tcp 指令判断实际状态值是否位于两端。如果位于两端,则在同一秒内马上改写。

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

优化成本

我们发现右边的那块芯片一共有 10 行代码,相比于 MC4000 的最大容量只多了一行代码。如果我们能想办法压缩掉一行代码,那么就可以替换成 MC4000,节省两块钱成本了。

突破口在于右边那块芯片的两句 tcp 指令上,我们现在要想办法压缩成一句,把【伪三态】变成【真正的三态】。但是在这个案例里,中间态有两种啊,3 秒和 4 秒都是中间态。如果我们能把 1~6 秒这六种状态改写成 1、2、3 三种状态,然后把状态值发到右边上去,就能实现真正的三态。

我们需要想办法找到一个公式,建立如下表所示的时间→状态值映射:

聪明的你,很快就发现了这样一条规律:

状态值等于时间值 +1 后除以 2 并向下取整的值!

然而我之前就说过,MC 系列芯片里只有加、减、乘三则运算,没有除法运算。不过,MC 系列芯片倒是提供了一些和十进制位运算相关的指令,用它们可以实现一些特定的除法及取余运算。

取位指令:

dgt I/R/P,取得 acc 寄存器的个/十/百位数,保留正负号,并覆盖原先的值。操作数为 0 时取个位,操作数为 1 时取十位,操作数为 2 时取百位,操作数为其他数时则将 acc 归零。

置位指令:

dst I1/R1/P1 I2/R2/P2,将 acc 寄存器中的某一位置为特定的值。位数由第一个操作数决定,0~2 分别表示个位/十位/百位,若在此范围外,则不执行任何操作。具体设置的值由第二个操作数决定,会只看最低位,忽略最高位,同时会将数字的符号设置为和该数一致。

下表详细说明了当 acc 为 123 时,执行不同的 dgt 和 dst 指令后的结果:

问题来了,这些位运算指令和除以 2 并向下取整有什么关系?其实,除以 2 相当于乘以 5 再除以 10 向下取整。与此同时,当原数小于 100 时,【取十位】就相当于【除以 10 向下取整】。进而推理可得:当原数小于 20 时,【乘以 5 再取十位】就相当于【除以 2 向下取整】!而我们的时间间隔只有 1~6 秒这几种状态,远小于 20 这个上限值。现在我们把映射公式改写成这样:

然后你又想到了:既然最后的状态值不是跟 time 而是跟 time + 1 呈等比关系,那我为何还非要从 0 开始计时而不从 1 开始计时呢?这样就把额外的 +1 操作去掉了。

再进一步:既然最终计算状态值时我总是要把时间 ×5,那我为什么还非得 1 秒 1 秒计时,每个时钟周期计 5 秒不香吗?计时也改为从 5 开始计!这样最后直接 dgt 1 就得到状态码了,什么 add 1 啊,mul 5 啊都是冗余操作!

于是你洋洋洒洒地写下了这样的代码:

学了一个 dgt 指令后,你惊奇地发现,何止成本降下来了,明明是三项指标全面下降了好不好!

评论 (0)

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

上拉或点击查看更多