Skip to content

Latest commit

 

History

History
123 lines (84 loc) · 7.34 KB

File metadata and controls

123 lines (84 loc) · 7.34 KB

第 9 节

本节最后修改于 2023 / 07 / 25

条件的进阶逻辑运算

上节讲了与、非和或的实现,我们还知道世界上有与非、或非、异或和同或等逻辑,那么能不能在我的世界中通过与、非和或组合出这些呢?

与非

$$A \ \mathrm{nand} \ B=\mathrm{not}\ (A\ \mathrm{and}\ B)$$

# 例子
# 如果重工业玉米并非同时有熊孩子标签和tnt,也就是“有熊孩子标签”与非“背包有tnt”为真,提示“重工业玉米简直是风流倜傥英俊潇洒,人见人爱花见花开”

[~,~,~,~] clear @a[name=重工业玉米] tnt -1 0
[+,L,+,0] tag @a[name=重工业玉米,tag=熊孩子] add T_8 //得到A与B的标签
[+,L,-,0] execute @a[name=重工业玉米,tag=!T_8] ~~~ say 重工业玉米简直是风流倜傥英俊潇洒,人见人爱花见花开
[+,L,-,0] tag @a[tag=T_8] remove T_8

看起来我们就轻松地实现了与非。

或非

$$A\ \mathrm{nor}\ B=\mathrm{nor}\ (A\ \mathrm{or}\ B)$$

# 例子
# 如果重工业玉米既没有熊孩子标签也没有tnt,也就是“有熊孩子标签”或非“背包有tnt”为真,提示“重工业玉米英俊的面庞在我心中挥之不去,如同静夜月光,照亮了我的心房”

[~,~,~,~] clear @a[name=重工业玉米] tnt -1 0
[+,L,+,0] tag @a[name=重工业玉米] add T_E //得到A或B的标签
[+,L,-,0] tag @a[name=重工业玉米,tag=熊孩子] add T_E //得到A或B的标签
[+,L,-,0] execute @a[name=重工业玉米,tag=!T_E] ~~~ say 重工业玉米英俊的面庞在我心中挥之不去,如同静夜月光,照亮了我的心房
[+,L,-,0] tag @a[tag=T_E] remove T_E

或非的实现也比较简单。

异或

$$ A \ \mathrm{xor} \ B =(\mathrm{not}\ (A\ \mathrm{and}\ B))\ \mathrm{and}\ (A\ \mathrm{or}\ B) $$

# 例子
# 如果重工业玉米熊孩子标签和tnt二者只有一个,也就是“有熊孩子标签”异或“背包有tnt”为真,提示“0.5秒与他的擦肩而过,我的脑海中便深深烙下了他的身影。不知为何,即便不去确认,我也心中了然:他就是重工业玉米了”

[~,~,~,~] clear @a[name=重工业玉米] tnt -1 0
[+,L,+,0] tag @a[name=重工业玉米] add T_E //得到A或B的标签
[+,L,-,0] tag @a[name=重工业玉米,tag=熊孩子] add T_E //得到A或B的标签
[+,L,-,0] clear @a[name=重工业玉米] tnt -1 0
[+,L,+,0] tag @a[name=重工业玉米,tag=熊孩子] add T_8 //得到A与B的标签
[+,L,-,0] tag @a[name=重工业玉米,tag=!T_8] add T_7 //得到非(A与B)的标签
[+,L,-,0] execute @a[name=重工业玉米,tag=T_E,tag=T_7] ~~~ say 0.5秒与他的擦肩而过,我的脑海中便深深烙下了他的身影。不知为何,即便不去确认,我也心中了然:他就是重工业玉米了
[+,L,-,0] tag @a[tag=T_E] remove T_E
[+,L,-,0] tag @a[tag=T_8] remove T_8
[+,L,-,0] tag @a[tag=T_7] remove T_7

这就是异或的实现。


发现在指令编写到一定程度时,有条件命令方块基本不会再出现了,我们会一直以选择器的形式进行条件运算。选择器一般的用法是标签。那么对于着繁多的标签和运算,怎么才能防止自己犯迷糊呢?可以使用表达式作为标签的名称,来表示含义,这样可以使运算的“操作数”和“返回值”都变得非常清晰,甚至让我在计算中有一丝享受的感觉。

原始的思想是:使用大写字母,例如ABCD来表示条件;使用andornot来表示运算符。这样子如果有一个人带标签AandB,我们就能清晰的知道这个人的身份——既满足 $A$ 条件,也满足 $B$ 条件。那么既不满足 $A$ 条件,也不满足 $B$ 条件的人所应该带的标签就应该是not(AorB)

以此类推,(非(A与B))与(A或B)的人应该就是(not(AandB))and(AorB)……真的吗?我们发现这个更简单的写法是AxorB。对于不同的表达式,结果却相同,那我们还不如用结果来命名。

我们知道对于 $A$$B$ ,他们只可能为两个值。我们可以称其 $真$$假$ ,也可以说是 $1$$0$ 。既然如此,对于 $A$$B$ 的运算的结果也一定是有限的。 $A\ \mathrm{and}\ B$ 随机搭配,可能有 $1\ \mathrm{and}\ 1$$1\ \mathrm{and}\ 0$$0\ \mathrm{and}\ 1$$0\ \mathrm{and}\ 0$ 四种可能,结果就是 $1$$0$$0$$0$ 四种可能。我们就可以说 $A=[1,1,0,0]$$B=[1,0,1,0]$$A\ \mathrm{and}\ B=[1,0,0,0]$ 。那么对于结果相同的标签AandB(AxorB)andA等等就都可以改写成1000

这种并列计算手工算有点麻烦了,我为此搞了一个在线并列计算器。点击左下角“导入基础配置”后将列宽设置为4,在右边表达式栏里即可输入表达式。比如A and B或者~not (A or B)等。点击计算即可得到结果。

1000有点长,我们就可以用十六进制表示为8。于是标签就可以叫T_8,仅仅三个字符的标签就可表示任意一类人群。

在命令方块串的最后,我们别忘了把这些临时标签都去掉。

逻辑运算对照表

读者可自己尝试将标签T_0~T_F都用指令实现出来,相信对上面段所介绍的逻辑运算会有更深的理解。

下方表格显示了标签T_0~T_F分别包含和排除了哪些情况的实体,还有各个标签的表达式。

标签 运算结果 全部符合 只符合 A 只符合 B 全都不符 最简表达式
T_0 0000 排除 排除 排除 排除 0
T_1 0001 排除 排除 排除 包含 非(A或B)
T_2 0010 排除 排除 包含 排除 (非A)与B
T_3 0011 排除 排除 包含 包含 非A
T_4 0100 排除 包含 排除 排除 A与(非B)
T_5 0101 排除 包含 排除 包含 非B
T_6 0110 排除 包含 包含 排除 (A或B)与(非(A与B))
T_7 0111 排除 包含 包含 包含 非(A与B)
T_8 1000 包含 排除 排除 排除 A与B
T_9 1001 包含 排除 排除 包含 (非(A或B))或(A与B)
T_A 1010 包含 排除 包含 排除 B
T_B 1011 包含 排除 包含 包含 (非A)或B
T_C 1100 包含 包含 排除 排除 A
T_D 1101 包含 包含 排除 包含 A或(非B)
T_E 1110 包含 包含 包含 排除 A或B
T_F 1111 包含 包含 包含 包含 1

可以发现这个表具有上下对称性,这是因为对于任意十六进制数 $n$ ,都有

$$n =\ \sim (0\mathrm{x}F - n)$$

也就是说,对于任意 $n$ 来说, $15-n$ 就是对 $n$ 进行取反的得数。

我们可以验证一下,比如选择 $0\mathrm{x}3$ 来验证:

$$\begin{aligned} & \quad \ (\sim\ (0\mathrm{x}F-0\mathrm{x}3)) \newline &= (\sim 0\mathrm{x}C) \newline &= (\sim 0\mathrm{b}1100) \newline &=0\mathrm{b}0011 \newline &=0\mathrm{x}3 \newline \end{aligned}$$

可以发现是成立的。所以如果我们已实现了T_ $n$ ,那我们就不需从头实现T_ $(0xF - n)$ ,只要对前者进行非运算就能得到后者。

类似的情况还有很多。实现一个标签后就可用于计算另一个标签。使用上文中提到的并列计算工具或者直接手动进行演算,找到运算最少的方法,可以让标签的实现更加简单。

到现在为止我们一直在研究两个条件之间的运算。那么三个以上的条件怎么办呢?其实多个条件的运算就是多来几次两条件运算。只要弄懂了两条件运算,就能套到其他多个条件的运算中,一样解决。

下一节