因为这次Hackergame2023涉及到了这款游戏,所以特地学习一下里面的逻辑系统

本文章为b站系列视频【Mindustry】逻辑入门的笔记

下面是该视频传送门

变量和关键字

变量

手动链接的自动命名

当我们修建一个处理器后,就可以单击旁边的方块进行手动链接

方块上会被自动设置变量名

我们可以在处理器中使用变量名指代这些方块

变量名一旦设置好,就无法修改

根据链接的排序使用Get Link指令命名

使用Get Link指令,我们可以根据链接顺序给方块手动命名

例如此处,我们将第一个链接的命名为x1变量,第二个命名为x2

指令执行过程中的赋值

我们也可以使用变量名去记录指令执行过程中的各种运行结果值

关键字

游戏中的各种关键字都以@符号开头

各种单位以及方块的名字都有对应的关键字

除了具体物件,还有以下其他常用关键字

关键词名称 含义
@time 1970年至当前时间点经过的毫秒数
@x (某物体的)x坐标
@y (某物体的)y坐标
@this 处理器自身
@thisx 处理器自身的x坐标
@thisy 处理器自身的y坐标
@unit 当前所链接的单位

指令

Mindustry中的指令为顺序执行,且到达末尾后会从头开始,循环往复

常见指令

Jump

Jump指令用于跳转到另一个指令

Jump指令会自带一个if的判断条件,如果为True,则执行Jump

在游戏中,可以从Jump后拖出一个箭头,用来指向跳转的目标指令

End

End指令用于跳过后续指令,立即返回开头执行

Sensor

Sensor用于从建筑或单位中获取数据

该指令的语法格式为

1
result = @state in target

其中result为用于记录取出的状态信息结果的变量

@state用于指定目标的某个状态

target用于指定目标

此处状态关键字可以选的内容非常多

下面是一些关键字,省略了和战斗相关的

关键字名称 含义
totalItems 储存物品的总量
totalLiquids 液体总量
totalPower 目标存储的电量
PowerNetIn 目标所在电网的发电量
ammo 弹药量
process 工厂、钻头等的进度
timescale 超速程度
enable 目标的开关状态
config 目标的选项,常用于分类器或装卸器

Control

Control指令用于控制元件状态

该指令的语法格式为

1
2
set @state of target
具体参数

其中@state用于指定目标的某个状态

target用于指定目标

不同的状态拥有不同的参数格式

这里需要用到的是enable和config两个状态

Set

set用于给变量赋值,可以将变量赋给变量

Operation

operation对变量进行数值计算的操作

指令界面操作

通过拖动指令,我们可以很方便地改变指令执行顺序

单击复制按钮会立刻在该指令下方复制一个相同的指令

可视化

文字信息

信息板可以用来显示输出的文字消息

print指令用于输出字符串、数字、关键字或者变量

print Flush用于选择输出目标

print中传入的字符串需要使用双引号""包裹

这两个指令的运行逻辑是,执行print指令会将输出内容暂时存储到缓冲中

print Flush则会将当前存储的所有内容都输出出来,并清空缓冲空间

图像

逻辑显示屏可以用于输出图像

相关指令为DrawDraw Flush

具体的绘图参数就不做介绍了,因为在Hackergame中的题目中没有涉及

简单逻辑

开关控制元件

流程图:

简化后的流程图:

Hackergame2023 异星歧途

整个地图的概览如下

我们需要控制红框中的那些开关,使得各个部分正常工作

Part1

首先看第一部分

这一段的工作元件如下图所示

运输过来的煤炭给火力发电机供电,进而产生电力,电力则通过电线传输给下一部分

查看该微型处理器以及其链接的方块

该火力发电机受到微型处理器的控制,命名为generator1,同时开关switch1switch8也在控制范围内

微处理器中的命令如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sensor s1 switch1 @enabled
sensor s2 switch2 @enabled
sensor s3 switch3 @enabled
sensor s4 switch4 @enabled
sensor s5 switch5 @enabled
sensor s6 switch6 @enabled
sensor s7 switch7 @enabled
sensor s8 switch8 @enabled
jump 18 equal s1 false
jump 18 equal s2 true
jump 18 equal s3 false
jump 18 equal s4 true
jump 18 equal s5 true
jump 18 equal s6 false
jump 18 equal s7 true
jump 18 equal s8 false
control enabled generator1 1 0 0 0
end
control enabled generator1 0 0 0 0
end

目标是让generator1的enable状态置为1

而前面这些jump语句都会跳到18,导致generator1的enable状态为0

所以我们就需要使得这些jump的判断条件为False

此时开关s1到s8的值应该置为10100101

成功工作!

Part2

接下来看第二部分

很显然,抽水机和涡轮发电机需要同时工作,进而产生电力并传给下一部分

我们需要使panell和generator1的enable置为1

查看逻辑处理器的指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
sensor sw1 switch1 @enabled
sensor sw2 switch2 @enabled
sensor sw3 switch3 @enabled
sensor sw4 switch4 @enabled
sensor sw5 switch5 @enabled
sensor sw6 switch6 @enabled
sensor sw7 switch7 @enabled
sensor sw8 switch8 @enabled
op shl t sw1 7
set number t
op shl t sw2 6
op add number number t
op shl t sw3 5
op add number number t
op shl t sw4 4
op add number number t
op shl t sw5 3
op add number number t
op shl t sw6 2
op add number number t
op shl t sw7 1
op add number number t
set t sw8
op add number number t
set en 0
set i 0
jump 33 greaterThanEq i 16
op pow fl0 i 2
jump 31 notEqual fl0 number
set en 1
jump 33 always x false
op add i i 1
jump 26 always x false
op equal fl1 0 sw1
op equal fl2 0 sw6
op or fl3 fl1 fl2
jump 38 equal fl3 0
set en 0
control enabled generator1 en 0 0 0
control enabled panel1 en 0 0 0
end

我们需要将其翻译为更通俗易懂的python语言

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
switchs = [0,0,0,0,0,0,0,0]
number = 0
for i in range(switchs):
t = switchs[i]<<(7-i)
number += t
en = 0
i = 0
while(i<16):
fl0 = i^2
if fl0 != number:
i += 1
continue
en = 1
fl1 = (0==switchs[0])
fl2 = (0==switchs[5])
fl3 = fl1 or fl2
if fl3 ==0 :
print("success!")

那么我们需要满足两个条件:en = 1fl3!=0

前一个条件决定了number为一个平方数,而后一个条件则限制了sw1和sw6必须均为1

这里我们可以使用爆破脚本找到满足条件的开关序列

需要注意的是switch8也在右侧的处理器范围内,一旦置为1,右侧模块则会爆炸

我们可以为该部分编写如下爆破脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import itertools
import gmpy2

dic = '01'
for x in itertools.product(dic, repeat=8):
switchs = ''.join(x)

number = 0
for i in range(8):
t = int(switchs[i]) << (7 - i)
number += t
if gmpy2.iroot(number,2)[1] \
and gmpy2.iroot(number,2)[0]!=0 \
and int(switchs[0])==1 \
and int(switchs[5])==1 \
and int(switchs[7])==0:
print(switchs)
exit()

得到正确序列11000100

Part3

接下来是第三部分

本段的结构更为复杂,需要我们深入理解工作原理才行

想要恢复电力,我们需要让反应堆1和2运作起来,也就是reactor1和2的enable需要置为1

但是反应堆需要散热,否则会爆炸

而散热则需要满足两个条件:冷冻液混合器工作冷冻液原料和水能够运输到冷冻液混合器,同时冷冻液和水不会分流浪费

翻译为元件状态则是mixer1、extractor1和gate1的enable置为1分流导管condult1和condult2的enable置为0

gate1为反溢流门,所以应该置为0

最后反应堆也需要原料钍,所以conveyor2的enable设为1

而那两天飞机则可有可无

我们再来看处理器内的指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
sensor sw1 switch1 @enabled
sensor sw2 switch2 @enabled
sensor sw3 switch3 @enabled
sensor sw4 switch4 @enabled
sensor sw5 switch5 @enabled
sensor sw6 switch6 @enabled
sensor sw7 switch7 @enabled
sensor sw8 switch8 @enabled
sensor sw9 switch9 @enabled
control enabled conveyor2 sw1 0 0 0
control enabled gate1 sw2 0 0 0
op equal nsw3 sw3 0
control enabled reactor1 nsw3 0 0 0
control enabled reactor2 nsw3 0 0 0
control enabled conduit1 sw4 0 0 0
control enabled conduit2 sw4 0 0 0
control enabled mixer1 sw5 0 0 0
control enabled extractor1 sw6 0 0 0
control enabled meltdown1 sw7 0 0 0
control enabled meltdown2 sw7 0 0 0
op equal result sw8 sw9
jump 28 equal result true
control enabled mixer1 0 0 0 0
control enabled conduit2 1 0 0 0
control enabled reactor1 1 0 0 0
control enabled reactor2 1 0 0 0
control enabled conveyor2 1 0 0 0
wait 5
end

sw1为1,sw2为0,nsw3为1,则sw3为0

sw4为0,sw5wei1,sw6为1,sw7为1

Jump的条件需要满足,所以result为True,sw8为0

此时序列为10001110

正常工作!s

Part4

最后一部分则类似于一个迷宫,需要我们找到一个正确的电力传输路径

乍一看,我们能找到这题红色路径,接下来就是思考如何让路径上的节点工作

首先是switch3和4,他们置为1能让下图中框住的部分联通

接下来我们需要让下图中标红的线路工作

要想让红星的火力发电机工作,就需要关闭焚化炉3

而焚化炉3被涡轮发动机控制,所以需要关闭涡轮发动机,此时控制两个煤炭能源旁的溢流门即可

打开焚化炉2和4就能让涡轮发电机关闭,而这需要关闭焚化炉1

所以switch1为0,switch2为1

下面该思考如何连通下图的电路

我们需要关闭焚化炉3,即切断其旁边电力节点的电源

这需要我们打开焚化炉1、2和4,即swtich6、7、8均为1

此时开关序列为01110111

成功通电!

最终总的开关序列为10100101110001001000110001110111

启动反应堆,并从提交网站获得flag