14 KiB
随机数性质:怎样从坐标图案反推种子候选
前面的 01–04 在做同一件事:给定一批种子和坐标,把它们检查得更快。这一章换一个角度:如果我们已经知道哪些坐标应该是史莱姆区块,能否利用随机数公式,先排除大量种子,再求出值得检查的候选?
我们以一个固定坐标的实心 5×5 图案为例。目标是寻找一个世界种子,让这 25 个格子同时满足要求。我们不知道每格产生的随机数具体是多少,只知道它们应该通过史莱姆判断。因此,这里的“反推”是根据多个条件缩小候选范围,结果可能有多个种子。
当前方法分成三步:筛低 18 位的可能取值,补上中间 17 位,再求出高 13 位的共同解。 最后执行完整的 Java Random 验证。
下面解释筛选和求解的过程,以及每一步的数学依据。首次输出筛选还没有完整覆盖拒绝重抽的例外;这个限制在文末说明。
1. 先区分种子、内部状态和随机输出
对坐标 $(x_i,z_i)$,原始史莱姆公式先计算坐标项:
T(x_i,z_i)=F(x_i)+G(z_i).
坐标项包含平方、乘法和加法,必须遵循原始 Java 的整数回绕与符号扩展规则,完整说明见 OUTER_SUM.md。下面用 d_i=T(x_i,z_i) 表示第 i 格的坐标项。
设世界种子的低 48 位为 $w$,合并史莱姆公式与 Java Random 初始化中的两个 XOR,得到:
A=\mathtt{0x5DEECE66D},\qquad
C=A\mathbin{\mathrm{xor}}987234911=\mathtt{0x5E434E432}.
每个格子的首次随机输出按下面三步产生:
u_i=((w+d_i)\mathbin{\mathrm{xor}}C)\bmod2^{48},
v_i=(Au_i+11)\bmod2^{48},
q_i=\left\lfloor v_i/2^{17}\right\rfloor.
这三个数的含义不同:
| 符号 | 含义 |
|---|---|
w |
待求的世界种子低 48 位 |
d_i |
第 i 格的坐标项,坐标确定后就能计算 |
u_i |
Random 初始化后的 48 位内部状态 |
v_i |
内部状态推进一次后的结果 |
q_i |
取出 v_i 的高 31 位得到的首次输出 |
其中,mod 表示取余数。例如 $8194\bmod8192=2$。模 2^k 相当于只保留一个数的低 k 位。
对被接受的首次输出,nextInt(10) 返回 $q_i\bmod10$,返回 0 就表示史莱姆区块。我们先利用“q_i 能被 10 整除”的条件生成候选,随后完整验证。
2. 为什么只考虑世界种子的低 48 位
Random 初始化时只保留低 48 位。因此,在同一个坐标上,如果两个原始世界种子 W_1,W_2 相差整数倍的 $2^{48}$,初始化状态就相同,以后的随机数序列也相同:
W_2=W_1+k2^{48}
\quad\Longrightarrow\quad
\mathrm{slime}(W_2,x,z)=\mathrm{slime}(W_1,x,z).
这条性质覆盖完整的随机数序列,包括拒绝重抽。搜索时可以先求低 48 位,原始 64 位输入的高 16 位对应同一组史莱姆判断结果。
这里讨论的是史莱姆判断的等价关系,不能据此断言整个 Minecraft 世界相同。
3. 把待求的 48 位分成三部分
按通常从高位到低位的书写顺序,这三部分是:
高 13 位 h | 中间 17 位 m | 低 18 位 p
对应数值关系:
w=p+2^{18}m+2^{35}h.
各部分的取值范围是:
0\le p<262144,\qquad
0\le m<131072,\qquad
0\le h<8192.
补上中间 17 位后,得到低 35 位:
\ell=p+2^{18}m,\qquad w=\ell+2^{35}h.
这三个部分的处理方式不同:低 18 位先筛选,中间 17 位目前主要枚举,高 13 位通过分段同余条件求解。
4. 低 18 位为什么能提前筛选
首次输出是:
q_i=v_i\gg17.
右移 17 位,就是去掉内部状态的低 17 位。于是,q_i 的最低位,对应 v_i 的第 17 位,位编号从 0 开始。
一个数要能被 10 整除,首先必须是偶数。我们只要知道 v_i 的低 18 位,就能知道它的第 17 位,从而判断首次输出的奇偶。
为什么计算这 18 位时,可以暂时不管世界种子的高位?因为加法、乘法和逐位 XOR 的低 k 位,只依赖输入的低 k 位。更高位不会反过来改变低位。
因此,令 $p=w\bmod2^{18}$、$d_{i,18}=d_i\bmod2^{18}$,只需要计算:
a_i=(p+d_{i,18})\bmod2^{18},
u_{i,18}=a_i\mathbin{\mathrm{xor}}(C\bmod2^{18}),
v_{i,18}=(Au_{i,18}+11)\bmod2^{18}.
最后检查:
v_{i,18}<2^{17}=131072.
小于这个分界值,说明第 17 位为 0,首次输出是偶数;否则就是奇数。
坐标项也参与计算。 这条性质说的是“种子的低 18 位,加上该格坐标项的低 18 位,足以决定首次输出奇偶”。换坐标后,结果可能改变。
5. 怎样从一个图案生成低 18 位候选表
只有一个“5×5”的形状还不够,需要知道锚点在哪。已有样例的锚点是:
(x_0,z_0)=(51069,419124).
图案包含的 25 个坐标为:
(x_i,z_i)=(x_0+\Delta x,z_0+\Delta z),
\qquad\Delta x,\Delta z\in{0,1,2,3,4}.
生成表的过程可以按下面的顺序理解:
- 计算 25 个坐标项,分别保留低 18 位。
- 尝试一种种子的低 18 位取值 $p$。
- 用这个
p检查 25 格的首次输出奇偶。 - 有一格为奇数,就淘汰这个 $p$;全部为偶数,就保存。
- 对
p=0,1,\ldots,262143重复这个过程。
这相当于为每格求出一个允许集合,再对 25 个集合求交。
看两个实际取值,就能理解“保留”和“淘汰”是什么意思:
种子的低 18 位 p |
检查的格子 | v_{i,18} |
结果 |
|---|---|---|---|
| 0 | (51069,419124) |
53282 | 偶数条件通过 |
| 0 | (51069,419125) |
178468 | 失败,整个 p=0 淘汰 |
| 3948 | (51069,419124) |
1118 | 偶数条件通过 |
| 3948 | (51069,419125) |
73664 | 偶数条件通过 |
p=3948 在其余格子上也通过,所以进入最后的候选表。
固定锚点 $(51069,419124)$,把要求通过的图案从 1 格逐步扩大到 5×5。每次保留已有格子,再加入扩大后新增的一圈格子,剩余取值数量如下。表中的 0 表示尚未加入任何格子条件,1 表示只检查锚点这一格:
| 要求通过的图案 | 剩余低 18 位取值数 |
|---|---|
| 0 | 262144 |
| 1 | 131072 |
| 2×2 | 20383 |
| 3×3 | 3385 |
| 4×4 | 427 |
| 5×5 | 84 |
单格恰好保留一半取值,是因为加坐标项、XOR 和奇数乘法在模 2^{18} 下都是一一对应的变换。继续加入格子,只会增加条件,所以候选数量只能保持不变或减少。
这 84 种取值就是“该坐标图案允许的世界种子低 18 位候选表”。
对固定图案,这一步可以作为预处理,只做一次。后续直接遍历这 84 种取值,给它们补上更高位,不必让所有完整种子先查一次表。
这里的 84 只适用于样例中的具体坐标。移动锚点或改变形状后,需要重新筛选;如果两个图案对应格子的坐标项低 18 位全部相同,就可以复用这张低位候选表,但完整随机输出仍可能不同。
6. 中间 17 位目前怎样处理
取出一个通过筛选的 $p$,再枚举:
m=0,1,\ldots,131071.
每次拼出一种低 35 位取值:
\ell=p+2^{18}m.
然后把这个 \ell 交给高 13 位求解器:是否存在某个 $h$,能让所有格子满足首次输出的模 10 条件?如果没有,就淘汰这个 $\ell$。
因此,当前没有另一张能直接消除中间 17 位枚举的通用表。样例需要处理:
84\times2^{17}=11010048
种低 35 位取值。低 18 位筛选避免了大量无效工作,但中间位的枚举成本仍然存在。
7. 为什么固定低 35 位后,高位可以单独求解
现在固定一种 $\ell$,世界种子写成:
w=\ell+2^{35}h.
选择 35 的原因是 XOR 常量 C 恰好需要 35 位:
2^{34}\le C<2^{35}.
它只会翻转低 35 位,不会碰到未知的高 13 位。
这里还要保留坐标加法的进位。对第 i 格,把 h=0 时的输入拆成:
(\ell+d_i)\bmod2^{48}=L_i+2^{35}H_i.
H_i 包含坐标加法产生的进位,也包含负坐标项在模 2^{48} 下的表示。加入 h 后,低位 L_i 不变,高位成为 $(H_i+h)\bmod8192$。
XOR 只改动 $L_i$,因此初始化状态满足:
u_i(h)=(u_i(0)+2^{35}h)\bmod2^{48}.
再推进一次状态:
v_i(h)=(v_i(0)+Ah,2^{35})\bmod2^{48}.
最后取首次输出,去掉状态低 17 位。新增量本来就是 2^{35} 的整数倍,不会改变被去掉的低位余数,所以:
q_i(h)=(q_i(0)+Ah,2^{18})\bmod2^{31}.
这里的 18 来自 $35-17$。
这是利用不同位域分离得到的平移关系。一般的 XOR 并不具有这种加法性质。若切在 34 位,C 仍会翻转未知部分的一位,上面的直接平移就不成立;切在 36 位等更高位置也可以分离,但剩下可解析的高位就更少了。
8. r_i,b_i 是怎样实际算出来的
它们来自一个确定的计算结果。选定 \ell 和第 i 格的坐标,先暂时令 $h=0$,按照原始公式计算:
u_i(0)=((\ell+d_i)\mathbin{\mathrm{xor}}C)\bmod2^{48},
v_i(0)=(Au_i(0)+11)\bmod2^{48},\qquad
q_i(0)=\left\lfloor v_i(0)/2^{17}\right\rfloor.
再把 q_i(0) 除以 $262144=2^{18}$:
r_i=q_i(0)\bmod262144,\qquad
b_i=\left\lfloor q_i(0)/262144\right\rfloor.
r_i 是余数,也就是输出的低 18 位;b_i 是商,也就是输出的高 13 位。例如,如果某格算出 $q_i(0)=524290$:
524290=2+262144\times2,
那么 $r_i=2,b_i=2$。这只是拆分数字的例子,不是前面样例某格的实测输出。
改变 h 后,该格的首次输出就是:
\boxed{q_i(h)=r_i+2^{18}\bigl((b_i+Ah)\bmod8192\bigr).}
b_i 是随机输出的一部分,h 是待求种子的一部分,不能把两者当成同一个数。 r_i,b_i 在当前 \ell 和坐标下固定,不同格子通常具有不同的 $r_i,b_i$,但所有格子共用同一个未知 $h$。
9. 为什么先求 $t$,再换回 h
为了让规则更容易处理,令:
t=Ah\bmod8192.
用 e_i 表示换元后该格输出的高 13 位:
e_i=(b_i+t)\bmod8192,\qquad
q_i=r_i+2^{18}e_i.
A 是奇数,和 8192=2^{13} 互质,所以这个换元只是在重新排列 8192 个编号,不会重复或遗漏。
具体来说:
A\bmod8192=1645,\qquad
1645\times4965=997\times8192+1.
因此,求到 t 后,可以直接换回:
\boxed{h=4965t\bmod8192.}
这里用到了“奇数乘数在模 2^k 下有逆元”的性质。如果完整状态 v 已知,同样可以用模逆恢复上一状态:
u=A^{-1}(v-11)\bmod2^{48}.
但首次输出已经丢掉状态低 17 位,而史莱姆观察只提供一个布尔结果。因此,当前搜索仍需组合多个格子的条件来求候选。
10. 每格到底对 t 提出什么要求
我们要让首次输出能被 10 整除。偶数条件已经由低 18 位筛选保证,现在还需要能被 5 整除。
因为:
2^{18}\equiv4\equiv-1\pmod5,
所以:
q_i=r_i+2^{18}e_i\equiv r_i-e_i\pmod5.
于是,每格提出的要求是:e_i 除以 5 的余数,必须与 r_i 相同。
完整写法为:
q_i\equiv0\pmod{10}
\iff r_i\equiv0\pmod2\ \text{且}\ e_i\equiv r_i\pmod5.
如果高位求解器单独接收一个没有预先筛过的低 35 位取值,发现某格 r_i 为奇数,就会立即返回无候选。
11. 回绕点是什么,为什么它会改变规则
考虑:
e_i=(b_i+t)\bmod8192.
可以把它想成一个从 0 数到 8191 的计数器。到 8192 时,就回到 0。
例如 $b_i=8190$:
t |
b_i+t |
取模后的 e_i |
|---|---|---|
| 0 | 8190 | 8190 |
| 1 | 8191 | 8191 |
| 2 | 8192 | 0 |
| 3 | 8193 | 1 |
| 4 | 8194 | 2 |
t=2 就是回绕点。一般来说,回绕点为:
\tau_i=8192-b_i.
点之前,$e_i=b_i+t$;从这个点开始,$e_i=b_i+t-8192$。由于 $0\le b_i,t<8192$,相加最多回绕一次。
把上一节的要求代入,就得到:
\begin{cases}
t\equiv r_i-b_i\pmod5,&0\le t<\tau_i,\
t\equiv r_i-b_i+2\pmod5,&\tau_i\le t<8192.
\end{cases}
第二种要求多了 2,是因为 $8192\bmod5=2$。若 $b_i=0$,回绕点在 8192,超出 t 的有效整数范围,所以这个格子在整个范围里都不回绕。
12. 用两个格子的数值例子,把求解串起来
下面的 r_i,b_i 是用于讲解的示意数值,不是 5×5 样例的实测参数。
第一格取 $r_1=2,b_1=8190$。它要求 $e_1\bmod5=2$,回绕点在 $t=2$:
t<2时,要求 $t\bmod5=2$。t\ge2时,要求 $t\bmod5=4$。
第二格取 $r_2=0,b_2=1$。它要求 $e_2\bmod5=0$,回绕点在 $t=8191$:
t<8191时,要求 $t\bmod5=4$。t\ge8191时,要求 $t\bmod5=1$。
把两格条件合并:
t 的区间 |
第一格要求的余数 | 第二格要求的余数 | 共同解 |
|---|---|---|---|
[0,2) |
2 | 4 | 无 |
[2,8191) |
4 | 4 | 区间中除以 5 余 4 的数 |
[8191,8192) |
4 | 1 | 无 |
因此,允许的 t 是:
t=4,9,14,\ldots,8189.
取 $t=4$,换回种子的高位:
h=4965\times4\bmod8192=3476.
检查两个格子的首次输出:
e_1=(8190+4)\bmod8192=2,\qquad
q_1=2+2^{18}\times2=524290,
e_2=(1+4)\bmod8192=5,\qquad
q_2=2^{18}\times5=1310720.
两个输出都能被 10 整除,所以 h=3476 是这两格共同允许的高位取值。真实图案对 25 格做同样的求交,最后拼成完整种子,再验证。
13. 最后说明首次输出模型的边界
上面的状态与输出变换恒等式是精确的。覆盖限制来自用“首次输出能被 10 整除”生成候选。
Java nextInt(10) 遇到:
q\ge2147483640=2^{31}-8
时,会拒绝这个输出,继续推进内部状态,再取一个输出。例如 2147483640 虽然能被 10 整除,也不会直接被接受。
因此会有两种情况:
- 首次输出符合我们的候选条件,但被拒绝,重抽后失败。最终精确验证会剔除这种假阳性。
- 首次输出不符合候选条件,例如是奇数,但处在拒绝尾部,重抽后成功。它可能在低位筛选阶段就被淘汰,最终验证无法补回这种漏解。
所以,当前流程准确验证所有输出的候选,但不能宣称已经找齐完整 Java Random 语义下的所有解。
低 18 位的 84 种取值、正文中的筛选数量和两个格子的示意例子,都可以按照上面的计算步骤独立核对。