某天在我B站的推荐上出现了这个视频:
这个视频将我的世界(Java Edition)中的钻石矿生成机制实属搞明白了,但是要想从原理上理解这个算法,需要一点基础知识。
在此先特别感谢up主“一只冰迷”的授权。
(一)钻石矿生成常识
一般地,版本为1.17以下的Java版中默认五个公理:
公理1:存在一个区块至少有一个钻石矿石;
公理2:存在一个区块,钻石矿石的位置是确定的;
公理5:所有区块的钻石矿生成高度在20m以下;
公理3:存在一个区块至少有一个青金石矿石,且青金石矿石的位置与钻石矿石的位置可以相互定位;
公理4:一个地图种子中的钻石矿石的位置是确定的。
为什么排序是个乱的?如果将这五个公理调换顺序就可以看出其重要性的排序了。
(二)钻石矿生成算法
我们可以推得如下定理:
定理1:地图种子和玩家所在区块决定钻石矿的生成位置。
公理1、公理4、公理2即可证明。
定理2:在高度为20m以下的矿区内只要青金石矿石就能找到钻石矿石。
公理3、公理5即可证明。
在这篇文章中我们先复现定理1,后面再复现定理2。
定理1可以用一个参数方程表示:
但是,这是一个定义式,真实情况是参数方程的求值及其困难。根据视频中作者提出的理论,我们先定义三个常数。
其中,第三个常数通常被为版本常数,这里用的是1.17的Java版本的对应常数,如果是1.16的Java版本将值改为60009。第二个常数通常称为等比数列常数。第一个常数通过因式分解可以分成四个质数的乘积:
故可以称之为四质数常数。
接下来就是最难的部分了。
根据视频中的理论,视频中告诉我们的是地图种子通过直接控制两个值从而间接控制钻石矿生成位置,视频里面设成(i,j)的意义在于类比向量的写法:空间直角坐标系内可以用三个单位向量的数乘表示所有向量。以下我将展开视频的流程一步一步讲透。
第一步:先求出种子常数:
.第二步:构造递推数列
,计算
。
第三步:求出地图种子控制常数组:
第四步:对玩家所在坐标取区块坐标,其中Floor函数为
。
第五步:求地图区块基数:
第六步:模仿前三步,将地图区块常数、构造数列第二项和第三项依次求出:
第七步:将目的地区块坐标和绝对坐标求出:
计算过程实质上是复合函数套来套去。最后得出的表达式是及其复杂的,这里不再写出来。至此已经将视频中的观点讲明白了。
检验:种子:-901706805885164814,版本1.17.1;
第一组:(-207,29,64)推出(-193,23,14),正确;
第二组:(-182,20,64)推出(-189,26,14),正确;
第三组:(-214,53,64)推出(-215,49,6),由于铁矿石生成与钻石矿石生成冲突优先生成铁矿,有钻石矿石的坐标为(-215,48,6)。