470 lines
14 KiB
Markdown
470 lines
14 KiB
Markdown
# 随机数性质:怎样从坐标图案反推种子候选
|
||
|
||
前面的 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](video/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 位分成三部分
|
||
|
||
按通常从高位到低位的书写顺序,这三部分是:
|
||
|
||
```text
|
||
高 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\}.
|
||
$$
|
||
|
||
生成表的过程可以按下面的顺序理解:
|
||
|
||
1. 计算 25 个坐标项,分别保留低 18 位。
|
||
2. 尝试一种种子的低 18 位取值 $p$。
|
||
3. 用这个 $p$ 检查 25 格的首次输出奇偶。
|
||
4. 有一格为奇数,就淘汰这个 $p$;全部为偶数,就保存。
|
||
5. 对 $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 种取值、正文中的筛选数量和两个格子的示意例子,都可以按照上面的计算步骤独立核对。
|