概要
マインクラフトではscoreboardコマンドを利用して、符号付き32bit整数を扱うことができます。
しかし、scoreboard players operationコマンド(以下scoreboard operationコマンドと表記)には四則演算と剰余演算が実装されていますが、ビット演算は実装されていません。
これでは将来、scoreboardを用いてビット演算を行いたいときに困るので自前で実装をします。
目次
- 環境
- 実装
環境
Minecraft Java Edition 1.19.4
実装
NOT演算
符号付き整数では負数の表現に2の補数表現を利用しているため、以下のような等式が成り立ちます。
¬A=-(A+1)
したがって以下のように実装できます。
scoreboard players operation $_not_ output = $_not_ input
scoreboard players operation $_not_ output *= $-1 const
scoreboard players remove $_not_ output 1
AND演算
特にこれといったテクニックはなく、愚直に1ビットずつ順に最上位から最下位ビットまでをみて$A ∧ B$を計算します。
愚直に書いているのでコードは少し長くなります。
長いので折り畳み
scoreboard players set $_and_ output 0
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players set $_and_ output -2147483648
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 1073741824
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 536870912
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 268435456
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 134217728
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 67108864
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 33554432
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 16777216
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 8388608
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 4194304
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 2097152
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 1048576
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 524288
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 262144
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 131072
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 65536
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 32678
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 16384
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 8192
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 4096
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 2048
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 1024
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 512
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 256
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 128
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 64
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 32
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 16
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 8
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 4
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 2
scoreboard players operation $_and_ input1 += $_and_ input1
scoreboard players operation $_and_ input2 += $_and_ input2
execute if score $_and_ input1 matches ..-1 if score $_and_ input2 matches ..-1 run scoreboard players add $_and_ output 1
OR演算
ANDと同じように愚直に実装しても良いですが、小技を使って楽をします。
まず、ド・モルガンの法則を使ってこのように変形します。
A ∨ B = ¬(¬A ∧ ¬B)
すると、今までに実装したAND、NOTの組み合わせで表現できるのでこれらを利用して実装します。
scoreboard players operation $_not_ input = $_or_ input1
function namespace:not
scoreboard players operation $_and_ input1 = $_not_ output
scoreboard players operation $_not_ input = $_or_ input2
function namespace:not
scoreboard players operation $_and_ input2 = $_not_ output
function namespace:and
scoreboard players operation $_not_ input = $_and_ output
function namespace:not
scoreboard players operation $_or_ output = $_not_ output
XOR演算
XORも愚直に実装しても良いのですが、ここでも小技を使って楽をします。
まずXORを次のように分解します。
A ⊕ B = A + B - ((A ∧ B) >> 1)
+,-は通常の整数の加減、>>は左ビットシフトです。
また、左ビットシフトはscoreboard operationの演算にはありませんがここでは2の累乗をかけることと等価です。
したがって以下のように変形できます。
A ⊕ B = A + B - 2(A ∧ B)
この変形のイメージとしては$A+B$の繰り上がり部分を引いて$A ⊕ B$を得ている感じです。
この形ならば、さっきまでに実装したものとscoreboard operationコマンドだけで表現できるのでそれらを利用して実装します。
scoreboard players operation $_xor_ output = $_xor_ input1
scoreboard players operation $_xor_ output += $_xor_ input2
scoreboard players operation $_and_ input1 = $_xor_ input1
scoreboard players operation $_and_ input2 = $_xor_ input2
function namespace:and
##左ビットシフト
scoreboard players operation $_and_ output += $_and_ output
scoreboard players operation $_xor_ output -= $_and_ output