末影人西瓜农场笔记

末影人西瓜农场笔记

注意!这篇文章仍处于施工中,具体完工时间未知

引言

末影人西瓜农场,指的是一类利用末影人死亡时必定掉落其手持方块物品形式的机制,让末影人捡起西瓜方块,随后杀死末影人的一种农场。本文将“小黑”这一末影人的俗称指代末影人,使用“小黑瓜机”或“瓜机”(无歧义时)指代末影人西瓜农场。

直接用活塞推动西瓜方块,只能掉落西瓜片,如果需要获得西瓜块的话,玩家还需要手动合成西瓜。作为唯一能全自动获得西瓜方块的方式,小黑瓜机可以避免传统推瓜农场在后续合成瓜块方面的工作量,能让西瓜的生产实现全自动。

小黑瓜机的产率在众多作物农场间并不出色。与普通作物农场相比,由于小黑瓜机涉及到了自然刷怪,因此无法简单地通过堆叠模块增加面积的方式提升效率;与普通刷怪塔相比,由于小黑在刷出后不能直接处死,而是需要放进瓜田里尝试捡一会瓜才能处死,这显著地增加了小黑存活时间,导致小黑瓜机无法像普通刷怪塔一样有着动辄几十万的产率。

本文主要内容如下:

  1. 剖析小黑瓜机中涉及的游戏机制
  2. 从理论角度分析影响小黑瓜机效率的因素
  3. 分析现有小黑瓜机的设计思路

一些术语

坐标

在分析中,常用的坐标有两种:一种是由 3 个实数组成的点坐标,如 (1.7, 2.5, 3.0),可以确定世界中的一个点;另一种则是由 3 个整数组成的方块坐标,如 (1, 2, 3),可以确定世界中的一个方块位置

在本文中,当我们描述一个坐标 $P$ 时,我们可以用 $P.x$ 代表该坐标的 x 值,$P.y$ 代表该坐标的 y 值,$P.z$ 代表该坐标的 z 值

在 MC 中,我们可以将一个点坐标转换为方块坐标,方法也很简单——将点坐标的三个坐标值向取整,得到三个整数,组合起来即为其所对应的方块坐标,即 $B = (\lfloor{A.x}\rfloor, \lfloor{A.y}\rfloor, \lfloor{A.z}\rfloor)$。这一坐标转换的几何意义也很明显:当点坐标 A 位于方块坐标 B 所代表的方块位置的 1x1x1 的立方体中时,点坐标 A 转换为的方块坐标即为 B,如下图所示:

方块坐标

本文将对这一 1x1x1 立方体称为方块坐标 B 对应的方格

对于实体而言,一个实体的实体坐标,指的是该实体碰撞箱下表面中心点所在的点坐标,这也是在召唤/传送的实体的时所使用的的坐标。对于玩家而言,玩家的实体坐标即为 F3 中显示的 XYZ 坐标

对于生物而言,其眼部坐标是一个通过如下方法计算出来的点坐标:x / z 为其实体坐标的 x / z,y 为其实体坐标的 y 加上其眼部高度。可以使用 F3 + B 开启碰撞箱显示来可视化地观察一个生物的眼部坐标,如下图所示,从生物的头附近延伸出去的那根蓝线的起点,即为这个生物的眼部坐标

村民的眼部坐标

AI

本文将使用以下与 生物 AI 相关的术语:

  • 行为:生物 AI 中的基本行为单元,如“随机移动”、“观察玩家”、“搜索目标”等行为,在代码中对应的基类为 EntityAIBase(MCP)、Goal(yarn、mojmap)。对于小黑而言,则存在着“捡起方块”、“放置方块”等行为
  • 两个生物之间存在视野接触:指的是两者的眼部坐标之间的连线不存在方块阻挡。这里的方块阻挡判断使用了采用方块的碰撞箱作为方块轮廓,忽略实体的射线检测

理论知识

末影人

小黑高 2.9m,宽 0.6m,眼部高度 2.55,为末地中唯一可自然生成的怪物。小黑的刷出条件与普通怪物一致,每次成群刷出的最大数量为 4

瞬移

小黑会在以下事件发生时,进行瞬移尝试:

事件 概率 尝试次数 瞬移指向
暴露在天空光下 与天空光亮度相关 1 随机
受到远程攻击伤害,如箭矢、三叉戟等 100% 64 随机
受到无视护甲的伤害,无论该伤害是否成功作用于小黑 90% 1 随机
正攻击玩家,距离玩家小于 4m,且玩家盯着小黑自己时 N/A 1 随机
正攻击玩家,距离玩家大于 16m,且离上次攻击玩家时的传送一段时间 N/A 1 目标玩家

小黑的瞬移尝试并不一定会成功:如果瞬移目的地不合法,则本次尝试将失败,小黑留在原地

由于小黑瓜机总是处于末地维度,也不依赖玩家的仇恨,因此我们仅需要考虑上表中与伤害相关的两种瞬移,可以发现它们都属于随机瞬移,仅仅是瞬移的尝试次数以及概率有所不同

小黑的随机瞬移分为两步执行,第一步是选取目标瞬移坐标,第二步为对目标坐标进行调整得到最终瞬移坐标

选取目标坐标 vec 逻辑的逻辑如下所示:

  1. 令 vec = 为小黑当前实体坐标
  2. vec.x += [-32, 32] 范围内随机实数
  3. vec.y += [-32, 32] 范围内随机整数
  4. vec.z += [-32, 32] 范围内随机实数
  5. 尝试瞬移至坐标 vec

根据上述逻辑,我们可以发现,小黑瞬移目标的范围近似为以小黑实体坐标为中心的一个 64x64x64 立方体。之所以说这是近似,是因为目的地 y 坐标的的可能取值是离散的,不能取到这一立方体中所有可能的 y 值

调整目标坐标 vec 得到最终瞬移目标的逻辑如下:

  1. 令目标坐标为 vec
  2. 令目标坐标所处于的方块坐标为 pos
  3. 找到 pos 下方的最高的一个 pos’,使得 pos’ 下方方块的材料种类为 可阻挡移动 的类型
  4. 如果 pos’ 不存在,传送失败,退出;否则继续执行
  5. vec.y = vec.y - (pos.y - pos’.y + 1)
  6. 判断若小黑坐标设为 vec 后,其位置是否合法:小黑碰撞箱需要不与任意方块的碰撞箱重合,且碰撞箱中不能含有流体
    • 如果位置合法,执行传送;否则传送失败

这部分逻辑也很移动,小黑并不想传送到半空中,在选定瞬移目标后会将其向下移动,找到一个“坚实”的落脚点,来作为最终的瞬移目的地。

从上述瞬移逻辑中我们可以看出,虽然小黑瞬移的目标坐标最多只能距离小黑 32m(切比雪夫距离),但是小黑传送的最终目的地是有可能下移至更低的位置。

捡起方块

小黑捡起方块的 AI 定义于名为 EndermanEntity.PlaceBlockGoal [1] 的行为中。当这一行为被执行时,小黑将根据如下步骤选取并尝试捡起身边的一个方块:

  1. 令小黑的实体坐标为 $A$,小黑将随机选取一个点 $B$,代表即将捡起的方块的位置,其中
\begin{align} B.x &= A.x + [-2, 2] \mbox{间随机实数} \\ B.y &= A.y + [0, 3] \mbox{间随机实数} \\ B.z &= A.z + [-2, 2] \mbox{间随机实数} \end{align}

如果我们绘制一个长宽均为 4,高为 3 的长方体 $R$,并令该长方体下表面的中心点与 $A$ 重合,那么 $B$ 即可视作此 $R$ 中的一个随机点。长方体 $R$ 的示意图如下:

捡起方块选择范围
  1. 令 $B$ 对应的方块坐标为 $B’$,则本次捡方块行为将尝试捡起位于 $B’$ 的方块。
  2. 进行如下射线判断,判断小黑自己能不能捡得到这一目标方块:
    1. 令 $A’$ 为 $A$ 对应的方块坐标,也即小黑的实体坐标所对应的方块坐标。可以理解为小黑脚底位于的方块的坐标。
    2. 令 $P_{start} = (A’.x + 0.5, B’ + 0.5, A’.z + 0.5)$,即取用 $A’$ 的 xz,再取 $B’$ 的 y,构造出一个方块坐标 $P$,最后取 $P$ 所代表方格的中心点。
    3. 令 $P_{end} = (B’.x + 0.5, B’.y + 0.5, B’.z + 0.5)$,即取 $B’$ 对应方格的中心点。
    4. 从 $P_{start}$ 至 $P_{end}$ 进行一次射线判定,射线判断可以认为是从起点到终点连一条线,看看该连线有没有与方块相交(被方块阻挡)。如果这一射线判定被除了 $P_{end}$ 所在的方块以外的方块阻挡,则判断失败,小黑无法捡到这一方块;如果射线判定未被任何方块阻挡,或者阻挡的方块即为 $P_{end}$ 所在的方块,那么判断成功,小黑能见到这一方块。

这部分判断的逻辑较为复杂,可以参考下图的实例进行理解。在下图中,紫色的点代表 $A$,绿色的点代表 $B$,紫色的框代表 $P$,绿色的框代表 $B’$,紫框与绿框间的淡灰线段的两个端点分别为 $P_{start}$ 与 $P_{end}$,同时这一线段也对应着射线判定时所代表的连线。

pick

现在小黑已经确定自己能捡得到这一个方块了,只剩下最后一步,判断自己能不能捡得起这一个方块:

  1. 判断目标方块是否带有 enderman_holdable 标签,若有则代表小黑能捡起这一方块;若无则小黑不能捡起这一方块,终止流程。注意,具有 enderman_holdable 标签的方块集合随着 MC 版本的变更有修改,如在 1.13 中所有的小型花并不具有这一标签。在 1.12 及以前,小黑能捡起方块集合是硬编码于代码中,而非由方块标签控制的
  2. 小黑把目标方块捡到手里,随后移除世界中的这个方块

在理解了上述目标方块选取的逻辑后,我们可以得到一些性质:

  • 一个方块是被小黑选中的概率至于其相对于小黑的位置有关,与方块的形状/属性无关
  • 一个方块所在方格与长方体 R 重合的越多,它被小黑选中的概率也越高。在该方块的方格完全处于 R 的内部时,它被小黑选中的概率达到最大值,为 $\frac{1}{4*4*3} = \frac{1}{48}$
  • 射线判断起点与重点的 y 坐标相等,它们的连线平行于水平面

既然谈到了射线检测,那我们也需要明确一下此处用小黑捡方块使用的射线检测的一些特点:

  • 忽略流体
  • 仅考虑方块的边界框,也即指针指向时渲染的黑线框。方块的碰撞箱将被忽略
  • 1.13 及以前,无碰撞箱的方块,如栅栏门,会被忽略

在判断射线是否会与方块相交的时候,常常会遇到如下图所示的临界情况:

临界情况

对于这种射线穿对角的临界情况,射线是否会被阻挡,在不同的 Minecraft 版本有着不同的答案,其结果甚至可能依赖于位置,因此难以总结出一个通用的规律。各位读者如果有需要,建议自行前往游戏中进行验证

本章节剩余部分以 Minecraft 1.13.2 为例,讨论方块距离小黑切比雪夫距离为 1 的情况。虽然这一规律并不适用于 1.14+ 的版本,但与其的思想是相同的

直接上结论:在 1.13.2 中,仅在射线在 x 轴方向投影指向 x 轴负半轴时,也即朝西,射线会与这两个方块相交,此时这两个方块之间任意一个都能阻拦射线;反之,若射线在 x 轴上的投影指向 x 轴正半轴,也即朝东,则射线将忽略这两个方块,此时这两个方块都无法阻拦射线。如下图所示:

临界情况性质

可以感性的理解这一特性:当且仅当射线朝向 x 正半轴时不会被方块阻拦。本文称上述方向依赖性的射线逻辑为“东向穿缝性”。这一个性质在设计小黑瓜机中的瓜布局时非常重要,对这一性质的充分利用可以有效地提升西瓜的密度,同时这也是不少小黑瓜机,如 dugged 服务器的瓜机,依赖于朝向的原因之一

本章节所使用的,用于展示末影人捡起方块射线端点逻辑的 scarpet 指令(在 fabric-carpet v1.4.8、v1.4.91 中测试可用):

1
2
3
4
5
6
7
8
9
10
11
12
13
/execute as @e[type=minecraft:enderman,distance=..16] run script run 
t=20;[x,y,z]=pos(p);
draw_shape('box',2,['from',[x-2,y,z-2],'to',[x+2,y+3,z+2],'color',0x2255AA88]);
draw_shape('sphere',2,['center',[x,y,z],'radius',0.02,'color',0xDD00DD88]);
if(world_time()%t==0,
[x1,y1,z1]=[x-2+rand(4),y+rand(3),z-2+rand(4)];
from=[floor(x)+0.5,floor(y1)+0.5,floor(z)+0.5];
to=[floor(x1)+0.5,floor(y1)+0.5,floor(z1)+0.5];
draw_shape('box',t,['from',from-[0.5,0.5,0.5],'to',from+[0.5,0.5,0.5],'color',0xFF33FFFF]);
draw_shape('box',t,['from',to-[0.5,0.5,0.5],'to',to+[0.5,0.5,0.5],'color',0x00DD00DD]);
draw_shape('line',t,['from',from,'to',to,'line',3,'color',0xDDDDDDFF]);
draw_shape('sphere',t,['center',[x1,y1,z1],'radius',0.02,'color',0x77FF77FF]);
)

放置方块

小黑放置方块的 AI 定义于名为 EndermanEntity.PlaceBlockGoal [2] 的行为中。当这一行为被执行时,小黑将根据如下步骤选取并尝试放置时其所持有的方块:

  1. 令小黑的实体坐标为 $A$,小黑将随机选取一个点 $B$,代表即将放置的方块的位置,其中
\begin{align} B.x &= A.x + [-1, 1] \mbox{间随机实数} \\ B.y &= A.y + [0, 2] \mbox{间随机实数} \\ B.z &= A.z + [-1, 1] \mbox{间随机实数} \end{align}

类似捡起方块的流程,如果我们绘制一个边长为 2 的立方体 $C$,并令该立方体下表面的中心点与 $A$ 重合,那么 $B$ 即可视作此 $C$ 中的一个随机点。立方体 $C$ 的示意图如下:

放下方块选择范围
  1. 令 $B$ 对应的方块坐标为 $B’$,则本次放置方块行为将尝试将方块放至 $B’$ 处
  2. 判断此次方块放置是否合法。一次合法的方块放置需要满足以下条件:
    1. $B’$ 处的方块为空气
    2. $B’$ 下方的方块不是空气,且为一个碰撞箱是完整的 1x1x1 方块
    3. $B’$ 所在环境对于小黑手持的方块而言,是一个合法的状态。如若小黑手持花方块,则 $B’$ 必须位于泥土类方块的上方
    4. (1.16.2-pre1 及以后)$B’$ 下方的方块不是基岩
    5. (1.16.2-pre2 及以后)$B’$ 所对应的方格范围,不与任何除了这只小黑外的实体的碰撞箱相交
  3. 执行方块放置,将小黑手持的方块放置于 $B’$ 处

下面是一个具体的例子,其中:

  • 紫点为点坐标 $A$
  • 蓝框为立方体 $C$
  • 绿点为点坐标 $B$
  • 绿框为方块坐标 $B’$ 所处的方格

小黑准备把手持的西瓜方块放置于绿框处,进行放置检查,发现 $B’$ 下方的方块是平滑石上半砖,不是一个碰撞箱完整的方块,因此这次方块放置的尝试失败

在设计小黑瓜机时,大部分情况下我们需要阻止小黑随处放置手里的西瓜。对此,一些常用的手段有:

  • 将所有小黑可触及的位置都放上方块,火把按钮什么的均可,因为小黑只能在空气方块位置放置方块
  • 确保不存在空气方块+碰撞箱完整方块的组合,例如用上半砖来替代实体方块来作为上表面完整的方块

如何阻止末影人乱放方块

本章节所使用的,用于展示末影人放下方块逻辑的 scarpet 指令(在 fabric-carpet v1.4.8、v1.4.91 中测试可用):

1
2
3
4
5
6
7
8
9
10
/execute as @e[type=minecraft:enderman,distance=..16] run script run 
t=20;[x,y,z]=pos(p);
draw_shape('box',2,['from',[x-1,y,z-1],'to',[x+1,y+2,z+1],'color',0x2255AA88,'line',4]);
draw_shape('sphere',2,['center',[x,y,z],'radius',0.02,'color',0xDD00DD88]);
if(world_time()%t==0,
[x1,y1,z1]=[x-1+rand(2),y+rand(2),z-1+rand(2)];
pos=[floor(x1),floor(y1),floor(z1)];
draw_shape('box',t,['from',pos,'to',pos+[1,1,1],'color',0x00DD00DD,'line',4]);
draw_shape('sphere',t,['center',[x1,y1,z1],'radius',0.02,'color',0x77FF77FF]);
)

仇恨

小黑对玩家生成的末影螨有着天然的仇恨,会主动移动至搜索范围内 视野可见 的末影螨处并对其进行攻击。与之对应的行为为 FollowTargetGoal [3],这一 goal 对目标实体的搜索范围为小黑的碰撞箱水平四方向扩展 generic.followRange 米,这里的 generic.followRange 为生物共有的一个属性,是在其生成时确定的一个定值。对于小黑而言,其计算算法如下:

1
2
3
4
5
// 22w16a(1.19快照)及以后
generic.followRange = 64 * (1 + nextGaussian() * 0.05)

// 22w16a(1.19快照)以前
generic.followRange = 64 * (1 + nextTriangular(0, 0.11485))

其中:

  • nextGaussian() 返回一个标准正态分布随机数
  • nextTriangular(0, 0.11485) 返回一个范围为 [-0.11485, 0.11485] 的三角分布随机数

下面的图表展示了 generic.followRange 的概率分布

≤ n 的概率 22w16a 以前 22w16a 及以后
64 50% 50%
62 26.60% 26.49%
60 10.57% 10.39%
58 3.04% 1.69%
56 0.62% 0%
52 0.0088% 0%
48 2.87E-7 0%

generic.followRange 的概率分布图

由此可见:

  • 22w16a 以前,由于涉及无上下界的正态分布,generic.followRange 的值可能会非常大,也有可能会非常小。这也是使用末影螨作为仇恨源的小黑瓜机总是时不时会有一些眼瞎小黑一直获取不到末影螨仇恨的原因——无界正态分布总有概率能让小黑的仇恨范围 generic.followRange 变成一个特别小的值
  • 22w16a 及以后,使用了有界的三角分布,因此 generic.followRange 不再可能取到过大或过小的值,其可能的取值范围约为 [56.65, 71.35]

生物 AI

生物的行为大多由其 AI 控制,末影人也不例外,如上文 末影人 章节中 捡起方块放下方块 这两个行为即是由 AI 控制的

对于设计小黑瓜机而言,我们关注的生物 AI 如何控制 行为 的执行,行为执行频繁会是怎样:是每 gt 都执行,还是每隔几个 gt 才执行;每次执行时是一定执行,还是有概率执行。毕竟,小黑“捡起方块”行为的执行频率,直接影响了小黑捡瓜的概率。

对于这部分的机制 <=1.13 跟 >=1.14 这两个版本范围间存在着不小的差异,具体分析如下:

1.13 及以前:

  • 每 3gt 将与执行中的目标不冲突,且可以开始的新目标,添加进执行列表
  • 每 1gt 清理执行列表中的目标,将不可继续的目标移出执行列表
  • 每 1gt 遍历并执行执行列表中的目标

1.14 及以后:

  • 每 1gt 停止不可继续执行的目标,并将它们移出执行列表
  • 每 1gt 将与执行中的目标不冲突且可以开始的新目标,添加进执行列表
  • 每 1gt 遍历并执行执行列表中的目标

其中:

  • 目标可以开始,指的是其 Goal#canStart [4] 函数返回结果为 true
  • 目标不可继续,指的是其 Goal#shouldContinue [5] 函数返回值为 false
  • 目标之间不冲突,指的是目标之间对生物的 控制类型 [6] 的集合交集为空。一个目标可以占用生物若干个控制类型,包括移动、视野、跳跃以及索敌这四种

对于小黑“捡起方块”这个目标而言:

  • 只有 $1 / 20$ 的概率可以开始,因为 PickUpBlockGoal#canStart 这个函数仅有 $1 / 20$ 的概率返回 true
  • 可以继续的概率与可以开始的概率相同
  • 不占用任何控制类型

可以发现,1.14 及以后的行为执行频率模型非常简易,可以直接视为每个行为每 gt 只要可以开始,那就可以执行。因此,对于小黑“捡起方块”这个目标而言,每个 gt 执行的概率都相同,等于其可开始概率 $1 / 20$

不过,1.13 及以前的行为执行频率模型就复杂不少了,虽然都是每 gt 都会清理 & 执行目标,但添加新的目标是每 3gt 才执行一次。目标添加进执行列表后,每个 gt 都得判断它是否还能继续,这会导致小黑“捡起方块”这种概率性可继续执行的目标,执行概率指数下跌

如果以 3gt 为周期,那么对于小黑“捡起方块”这个目标而言,有

时间 执行概率
gt0 $(1 / 20) = 0.05$
gt1 $(1 / 20) * (1 / 20) ^ 1 = 2.5 * 10 ^{-3}$
gt2 $(1 / 20) * (1 / 20) ^ 2 = 1.25 * 10 ^{-4}$
平均值 $0.01754$,约 $1/57$

是的,在 1.13-,小黑每 gt 执行“捡起方块”目标的概率仅有 $1 / 57$,与 1.14+ 的 $1 / 20$ 相比有着明显的差距,大概仅为 1.14+ 概率的 $1 / 3$。执行“捡起方块”目标并尝试捡瓜的执行概率直接影响了小黑捡起西瓜的成功率,这就是 1.13- 和 1.14+ 之间小黑瓜机概率差距大的原因之一

瓜苗

西瓜苗跟南瓜苗一样,共用着 StemBlock [7] 这个类,拥有着相同的生长逻辑。下文使用瓜苗一词来指代西瓜苗及南瓜苗

跟其他农作物一样,瓜苗的生长速度取决于其附近湿润耕地的数量,以及附近同种作物的数量。不防令其生长速度为 $s$,$s$ 越大则生长速度越快,那么对于瓜苗,我们可以通过如下流程计算出 $s$:

  1. 令 $s$ 为初值 $1$

  2. 统计瓜苗附近耕地的湿润值。统计瓜苗下方一格,水平方向切比雪夫距离 <= 1 的耕地。对于瓜苗正下方的耕地,若为湿润,则 $s$ 增加 $3$;若为干燥,则 $s$ 增加 $1$。对于范围内其余耕地,若为湿润,则 $s$ 增加 $0.75$。如下图左半边所示

    其中,耕地为湿润 / 干燥是由其方块状态 moisture 决定的,moisture 为 0 时耕地干燥,moisture 大于 0 时耕地湿润

  3. 统计瓜苗附近的同种作物。当以下条件任意一者满足时,将 $s$ 值除以 $2$

    • 瓜苗的南方或北方的作物(下图右侧粉圈)为同种作物,且瓜苗的东方或西方的作物(下图右侧蓝圈)为同种作物
    • 瓜苗的西北、东北、东南、西南处其中之一(下图右侧黄圈)的作物是同种作物

    其中,同种作物指的是方块类型相同的作物,比如西瓜苗跟南瓜苗不是同种作物,西瓜苗跟土豆也不是同种作物,但生长长度 age 不同的西瓜苗之间是同种作物

    值得一提,在 1.13 及以后,麻将把生长中的瓜苗和长了瓜的瓜苗拆分成了 2 个不同的方块类型,这导致西瓜苗(minecraft:melon_stem)和长了瓜的瓜苗(minecraft:attached_melon_stem)不再是同种作物,南瓜同理

  4. 生长速度 $s$ 计算完毕

生长速度计算流程

可以这样感性地理解生长速度的计算流程:周围湿润的耕地越多,营养就越多,生长速度就越快;附近的同种作物会争抢营养,导致生长速度下降

同其他作物一样,触发瓜苗生长的事件是随机刻。在瓜苗方块受到随机刻作用时,如果其光照条件满足要求,那么将会有 $\frac{1}{n}$ 的概率进行一次生长。其中:

  • 光照条件要求:
    • 1.12:瓜苗上方一格方块的亮度等级 >= 9。此处亮度计算包含天空光,考虑天空光衰减
    • 1.13:瓜苗上方一格方块的亮度等级 >= 9。此处亮度计算包含天空光,不考虑天空光衰减
    • 1.14+:瓜苗处的亮度等级 >= 9。此处亮度计算包含天空光,不考虑天空光衰减
  • $n = \left\lfloor{\frac{25}{s}}\right\rfloor + 1$,其中 $s$ 即为上文描述的生长速度

瓜苗进行生长时,首先会看看它的方块状态 age 值是否达到了最大值 7,若未达到,则将其 age 值 +1,生长结束;若 age 已达 7,瓜苗会随机挑选一个水平毗邻的方块坐标,尝试在次数结瓜。结瓜需要满足以下条件:

  • 结瓜处为空气。瓜只能长在空气里,不能挤掉已存在的方块
  • 结瓜处下方一格为泥土类型方块,包括耕地、泥土、砂土、灰化土、草方块这一类等含有 dirt 方块标签的方块

条件满足,那么瓜苗将进行结瓜,放置瓜苗方块、长了瓜的瓜苗方块;条件不满足,那么结瓜尝试失败,不会进行重试

至此,瓜苗的生长流程分析完毕。下面是一个具体的例子以供参考

生长速度计算例子

上图所示的瓜苗布局中,中心瓜苗的生长速度 $s$ 以及生长概率 $\frac{1}{n}$ 的计算流程如下

  1. $s$ 赋初值 $1$
  2. 统计瓜苗附近耕地的湿润值,$s$ 共增加 $7$,为 $8$
  3. 计瓜苗附近的同种作物,$s$ 折半,为 $4$
  4. $n = \left\lfloor{\frac{25}{s}}\right\rfloor + 1 = \left\lfloor{\frac{25}{4}}\right\rfloor + 1 = 6 + 1 = 7$

因此,中心瓜苗在每接受一次随机刻时,有 $1/7$ 的概率进行生长。由于其已达到最大 age 值,因此每次生长都将尝试长瓜。

考虑到中心瓜苗水平毗邻的 4 个位置只有 2 个位置为空气,因此尝试长瓜时,还需 2 / 4 的概率才能长出瓜来

令中心瓜苗每接受一次随机刻时的长出瓜的概率为 $p$,则 $p = \frac{1}{n} * \frac{2}{4} = \frac{1}{14}$

呱唧分析

农场结构

无论呱唧的结构,

无论采取怎样的呱唧设计思路,瓜机的结构都可以分为以下 3 个部分:

  1. 刷怪单元
  2. 捡瓜通道
  3. 处死模块

农场结构

我们称一个包含上述 3 个部分的最小可运行结构,为产瓜单元。通常来说,一个产瓜单元的独立性是比较强的

前提假设

下文对小黑瓜机分析的重点是,瓜机的效率上限计算,并以提升瓜机效率的最大值为设计目标。不妨作出下述的前提假设:

  • 刷怪上限有限。通常而言,这个上限值为 70,对应着单玩家所能提供的刷怪上限

  • 瓜机的规模足够大。本文分析的小黑瓜机设计均由多个独立的产瓜单元组成,产瓜单元之间耦合度很低,可以直接通过堆叠产瓜单元的手段来增加瓜机效率

    虽说一味地增加瓜机体积的收益是边际递减的,但在单元数量堆叠到一定程度时,其余条件就已经很接近理想情况了

  • 刷怪满上限。瓜机的规模足够大意味着刷怪面积是充足的,那么每当小黑数量降至怪物容量内时,新的小黑会很快地刷出来,继续顶满刷怪上限

    • 这意味着同时存在小黑数量的期望值等于怪物容量,即在每时每刻都存在约 70 只小黑
    • 在实际情况中,考虑到过量生成的情况,同时存在的小黑数量有可能超过怪物容量
  • 瓜田接近满瓜。考虑到同时存在的小黑数量是有限的,在瓜机规模足够大时,每个产瓜单元分到的小黑流量是很低的,这会导致瓜苗长瓜的速度明显高于小黑搬瓜的速度,进而导致瓜田是处于一个接近满瓜的状态

若无特殊说明,下文的分析均以上述假设为背景进行

理论效率计算

核心公式:

  • 瓜机产率(瓜/h) = 小黑刷怪速率(只/h) * 小黑捡瓜率(瓜/只)

刷怪公式:

[—][—][—][—][—][—]
[—][—][—][—][—][—]
[—][—][—][—][—][—]
[—][—][—][—][—][—]
[------------ 1h -----------]

  • 小黑刷怪速率(只/h),即每小时小黑生成数量(只) / 1 小时(h)
  • = 平均同时存在的小黑数(只) / 小黑平均存活时间(h)
  • = 平均同时存在的小黑数(只) / 小黑平均存活时间(h)
  • =
  • = 平均同时存在的小黑数(只) * 每小时游戏刻数(gt/h) / 小黑平均存活时间(gt)
  • = (72000 * 70) / 平均存活时间
\begin{align} 小黑刷怪速率 &= 每小时小黑生成数量 / 1小时 \ &= 1 小时小黑生成数量 / 1小时 \ &= 平均小黑数量 * &= 每小时的游戏刻数 / 存活时间 * 70 &= 72000 / 存活时间 * 70 \end{align}

其中存活时间以 gt 作为单位

捡瓜率:

瓜密度

小黑捡方块范围内有效瓜的总体积占比

冲突瓜

小红文

设计思路

基于末影螨仇恨的瓜机

使用末影螨吸引小黑最大的优点为,可以在主体结构不变的情况下轻易地增加大量刷怪面积。

缺点:小黑发现末影螨需要时间

总结:性价比高,上限低。

刷怪单元

捡瓜通道

处死模块

基于机械结构的瓜机

刷怪单元

捡瓜通道

处死模块

总结

参考


  1. EntityEnderman.AITakeBlock(MCP);EnderMan.EndermanTakeBlockGoal(mojmap) ↩︎

  2. EntityEnderman.AIPlaceBlock(MCP);EnderMan.EndermanLeaveBlockGoal(mojmap) ↩︎

  3. EntityAINearestAttackableTarget(MCP);NearestAttackableTargetGoal(mojmap) ↩︎

  4. EntityAIBase#shouldExecute(MCP);Goal#canUse (mojmap) ↩︎

  5. EntityAIBase#shouldContinueExecuting(MCP);Goal#canContinueToUse (mojmap) ↩︎

  6. 见函数 EntityAIBase#getMutexBits(MCP);枚举类 Goal.Control(yarn);枚举类 Goal.Flag(mojmap) ↩︎

  7. BlockStem(MCP);StemBlock(mojmap) ↩︎