Documentation
¶
Overview ¶
Package loot 提供加权随机抽取原语:抽卡 / 开宝箱 / 怪物掉落 / 直播抽奖。
核心是 Table[T]:每个物品带权重,按权重比例随机抽取。抽取用 Vose's Alias Method, 预处理 O(n) 建两张表后,每次抽取 O(1)(而非朴素前缀和 + 二分的 O(log n)), 海量抽卡场景下这是关键。
三种进阶能力(可选):
- 保底(pity):Puller 记录"连续多少次没出某稀有度",达阈值强制出一个该稀有度 物品——几乎所有商业抽卡都有的机制,避免非酋无限空手;
- 不放回抽取(DrawN):一次抽 N 个不重复(十连抽的去重语义);
- 有状态抽取器(Puller):把 pity 计数等状态封装,每个玩家一个。
Table 构建后只读、并发安全(Alias 表不可变);随机源默认 math/rand/v2(并发安全, 免播种);Puller 有内部状态,非并发安全(每玩家一个,天然隔离,或自行加锁)。
零值不可用:Table 用 NewTable 构造。
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrEmptyTable = errors.New("loot: table has no positive-weight items")
ErrEmptyTable 表内无有效物品(全部权重 <=0 或列表为空)。
Functions ¶
This section is empty.
Types ¶
type Puller ¶
type Puller[T any] struct { // contains filtered or unexported fields }
Puller 是带保底(pity)状态的抽取器:在 Table 之上记录"连续多少次没抽到 >= 目标稀有度的物品",达到 pity 阈值时,强制从"高稀有度子表"抽一个。
典型:抽卡保底——连续 89 抽没出 5 星,第 90 抽必出 5 星(pityLimit=89)。
Puller 有内部计数状态,非并发安全:每个玩家一个 Puller(天然隔离), 或调用方自行加锁。零值不可用,用 NewPuller 构造。
func NewPuller ¶
NewPuller 创建带保底的抽取器。 pityLimit:连续未出货达此次数时,下一抽强制出货(<=0 关闭保底,等价裸 Table)。 pityRarity:稀有度阈值,抽到 Rarity>=它视为出货。
若表内没有任何 Rarity>=pityRarity 的物品,保底无法触发(退化为普通抽取)。
func (*Puller[T]) Draw ¶
Draw 抽一次并维护保底计数:
- 若已连续未出货达 pityLimit 且存在高稀有度子表,强制出货(从高稀有度子表抽),计数清零;
- 否则正常抽;抽到 Rarity>=pityRarity 视为出货,计数清零;未出货则计数 +1。
返回抽到的 Item 与本次是否由保底触发(pity)。
type Table ¶
type Table[T any] struct { // contains filtered or unexported fields }
Table 是一张加权抽取表。构建后只读、并发安全。零值不可用,用 NewTable 构造。
func (*Table[T]) DrawDistinct ¶
DrawDistinct 不放回抽取 n 个互不相同的物品(按权重加权,已抽中的不再重复)。 n 超过表内物品数时,返回全部物品(数量 < n)。用于"十连里不重复"的场景。 复杂度 O(k·m)(k=抽取数,m=剩余物品数),不走 Alias(动态权重),适合 n 较小的连抽。