第四十四章 在Minecraft用指令算1+1=?
(注意:这一章很烧脑,建议在空闲时间大脑容量充足时阅读,最好阅读时在游戏内实地操作)
我们知道,记分板中所计入的玩家分数都是变量。既然是变量,那么多个变量是否可以互相运算呢?
答案当然是可以。Mojang也为这个运算功能单独提供了一个子命令:obr /eration(操作)
obr /eration的格式如下:
/scoreboard br /layers obr /eration <被跟踪的玩家或非玩家A:目标选择器><计分项a><计算方式><被跟踪的玩家或非玩家B:目标选择器><计分项b>
看着是不是有点迷糊?简单来说,使用obr /eration子命令的具体运算过程是这样的:
第一步:使用目标选择器指定目标A
第二步:指定计分项甲
(上面两步相当于将目标 A在计分项甲中的分数作为输入a。比如,假设目标A是张三,计分项甲是dummy型的“违法次数”,张三的违法次数是12,那么输入a的值就是张三的违法次数的值,即a=12。)
第三步:指定计算方式(或者说是指定操作)
第四步:使用目标选择器指定目标B
第五步:指定计分项乙
(上面的四、五步和一、二步同理,将目标 B在计分项乙中的分数作为输入b)
第六步:将输入a和输入b两个量按照指定的操作进行运算。
第七步:按照指定的操作更改输入a的和输入b的值。(大部分操作只会更改输入a的值,即把运算得出的值覆盖原本输入a的值)
举一个简单的例子:
/scoreboard br /layers obr /eration 张三 gold +=李四 gold
假设张三在gold计分项中的分数是1,李四也一样。那么这串指令运行过后张三在gold计分项中的分数将会变成2(1+1),但李四的分数还是1。
这个例子中,采用的操作(运算方式)是+=,即“求和”。具体是将输入a(张三的gold分数)和输入b(李四的gold分数)相加,得到结果c,并将结果c的值覆盖原本输入a的值。也就是说,这个“求和”是这么算的:
输入a =结果c =输入a +输入b
(注意,这不是正常的数学等式。在这里有一个运算的时间先后。即最左边的输入a是运算完成时的输入a,并不等于最右边刚开始运算时“输入a+输入b”中的输入a,两者是一新一旧,不能将它们认为是同一个“输入a”)
操作不止有求和(+=),它一共有九种:
(注:“⌊⌋”指向下取整。如⌊3.12⌋=3,⌊-4.82⌋=-5)
+=——求和
-=——求差(输入a =结果c =输入a -输入b)
(如:2 -= 1 ,结果就是2-1=1)
*=——求积(输入a =结果c =输入a ×输入b)
(如:2 *= 3,结果就是2×3=6)
/=——求商(输入a =结果c =⌊输入a ÷输入b⌋)
(如:24 /= 12,结果就是24÷12=2;17 /= 13,结果就是⌊17÷13⌋=1)
%=——求余(输入a =结果c =输入a mod 输入b =输入a -⌊输入a ÷输入b⌋×输入b。简单点的说法就是:输入a =(输入a ÷输入b)的余数)
[注:Java1.13.1版本更新中,%=的内部代码运算采用的某个方法从原本的%改成了Math.floorMod。不知道这会造成什么影响。我尚未在1.13.1和以上版本中进行相关实验。]
(如:17 /= 13,结果就是17-⌊17÷13⌋×13=17-1×13=17-13=4)
=——赋值(输入a =结果c =输入b。即把输入b的值覆盖到输入a上)[注:Java1.8以下版本没有]
(如:15 = 6,结果就是6)
<——取较小值(如果输入a ≥输入b ,输入a =结果c =输入b;如果输入a ≤输入b,输入a =结果c =输入a)[注:Java1.8以下版本没有]
(如:17 < 13 ,结果就是13)
>——取较大值(如果输入a ≥输入b ,输入a =结果c =输入a;如果输入a ≤输入b,输入a =结果c =输入b)[注:Java1.8以下版本没有]
(如:13 > 17 ,结果就是17)
><——互相交换值(输入a 和输入b值互换)[注:Java1.8以下版本没有]
(如 4 >< 19,结果是“输入a=19,输入b=4”)
这似乎有点烧脑?没关系,下面还有更烧脑的。obr /eration实际上是个很复杂的东西,将其了解透后你的逻辑运算能力应该能变强几分。
我们知道,目标选择器可以选择多个目标。而你有没有注意到,刚才我们所了解的不过都是输入a和输入b均都为1个的情况。那么如果输入a有多个,或是输入b有多个,甚至是输入a和输入b都有多个的时候,obr /eration又会怎样运算?
由于接下来的内容Minecraft Wiki并未记载(注:英文Minecraft Wiki有两行记载,但讲得过于简略),网上也搜不到相关内容,下面内容都是作者在Java1.12.2版本中实验得出的。如果你对此很感兴趣,你也可以自己尝试去做做实验,看看在其他版本下或其他情况下结果是否一样。
①当输入a有多个分数,而输入b仅有一个分数时
现在我们假设输入a有三个:
a₁=1
a₂=0
a₃=-1
输入b有一个:
b=3
我们对这三个输入a和输入b进行+=(求和)操作,最终得出来结果是:
a₁=c₁=a₁+b=1+3=4
a₂=c₂=a₂+b=0+3=3
a₃=c₃=a₃+b=-1+3=2
因此不难发现,当有多个输入a但只有一个输入b时,游戏将会把每个输入a均与输入b进行一次运算操作。
(注:这不是真正的实验过程,这已经被大大简化了)
②当输入a有一个分数,而输入b有多个分数时
我们假设输入a=1,输入b有三个:
b₁=2
b₂=3
b₃=-4
我们对这个输入a和三个输入b进行+=操作,最终得出结果是:
a=c=a+b₁+b₂+b₃=1+2+3+(-4)=2
不难发现,当输入a只有一个但输入b有多个时,输入a将与每个输入b都进行一次运算操作,再把最终得出的结果覆盖到原本的输入a上。
③当输入a和输入b均为多个分数时(该情况Minecraft Wiki并未记载):
我们假设输入a有两个:
a₁=1
a₂=0
输入b也有两个:
b₁=3
b₂=-2
我们也对它们进行+=操作,最终得出的结果竟然是:
a₁=c₁=a₁+b₁=1+3=4
a₂=c₂=a₂+b₁=0+3=3
没错!输入a和输入b多个的情况下,游戏只会选择一个输入b来参与运算。也就是说,在其他条件相同的情况下,该结果跟输入a多个但输入b只有一个的结果一模一样。
这应该算是个Bug吧......
对了,既然游戏只会选择一个输入b来参与运算,那么这个输入b会选择谁呢?
根据作者的测试,游戏会选择目标选择器排列的第一个输入b,这时候就要看你用的目标选择器。如果用的是@br /、@e、@a,就是就近原则;如果是@r,则是随机。
这个排列顺序在obr /eration中不只是用于选择输入b,它还用于在情况①下决定输入a们与输入b运算的先后顺序和情况②中决定输入a和哪些输入b先运算,哪些输入b后运算。
了解这些后,我们就可以来看一种升级版的情况①:
当输入a有多个,输入b有一个且这个输入b也是一个输入a时
这个情况是啥意思呢?简单来说,现在有张三李四王五,我们拿他们三的分数作为三个输入a,并把张三的分数也作为输入b。是不是复杂了起来?
我们假设有三个输入a,分别是:
a₀=-2
a₁=1
a₂=3
(按照下标数字从小到大参与运算)
而输入b就是a₁。
我们对它们两按照该情况进行+=运算,最终得出来以下结果:
a₀ⁿᵉʷ=c₀=a₀ᵒˡᵈ+a₁ᵒˡᵈ=-2+1=-1
a₁ⁿᵉʷ=c₁=a₁ᵒˡᵈ+a₁ᵒˡᵈ=1+1=2
a₂ⁿᵉʷ=c₂=a₂ᵒˡᵈ+a₁ⁿᵉʷ=3+2=5
上面两个式子中,为了让大家方便理解,我特别标上了old(旧)和new(新)来代表未运算和已运算的两个不同的量。
不难发现,当输入a有多个,并且输入b是众多输入a中的一个时,如果某个输入a与输入b运算时这个输入b所关系的输入a还没有运算,那么这个输入a将会与旧的输入b进行运算;如果某个输入a与输入b运算时这个输入b所关系的输入a已运算完成,那么这个输入a将会与新的输入b进行运算。
这读起来有点绕口啊。没关系,虽然现在你不一定看得懂,但只要你在游戏中实地做过实验你估计就懂了。
本章就到这里......了?
刚才的四个探究中,我们都在探究obr /eration在有多个输入和多个输出情况下会如何计算。一般来说,进行这种研究会用到命令方块。你知道的,命令方块运行指令成功后会输出结果,这个结果可能会影响到命令方块输出的红石信号强度。比如我们之前讲到的testfor指令,探测到有多少个实体就输出多强红石信号。
那么obr /eration在命令方块中执行成功是否会影响到命令方块输出的红石信号强度呢?
答案是:能!
经过作者的测试,obr /eration运行一次输出的红石信号强度,等于该次obr /eration计算的次数。比如情况①中,如果指令是在命令方块中运行,那么运行成功后命令方块将输出3级红石信号,因为obr /eration运算了3次。情况②输出的信号也一样,别看作者给出的只是一行式子,但是obr /eration仍然确确实实运算了3次。
这是一个冷门到极致的知识,冷门到连Minecraft Wiki也没有记载。当然我也不确定在新版本是否还有这个功能,也许已经被移除了呢?