教练,我想学抽卡

事情是这样的,最近开始玩明日方舟了,作为一个脸黑又贫穷的博士,如何使用有限的资源,使得自己的抽卡逻辑达到理论上的一个较优解,从而实现利益最大化,是一个可以深究的问题,故此研究一下其中的概率问题。

骰子概率问题

一个正 m 面体骰子,考虑每次投掷时任意一面出现的概率均为 $1/m$,且每次投掷时单次概率基数不变。

骰子投 1 次时某一数字已出现过的概率:

\[P_1 = \frac{m^0}{m^1}\]

骰子投 2 次时某一数字已出现过的概率:

\[P_2 = \frac{m^1 + (m-1) \times \boldsymbol{m^0}}{m^2}\]

骰子投 3 次时某一数字已出现过的概率:

\[P_3 = \frac{m^2 + (m-1) \times \boldsymbol{(m^1 + (m-1))}}{m^3}\]

骰子投 4 次时某一数字已出现过的概率:

\[P_4 = \frac{m^3 + (m-1) \times \boldsymbol{(m^2 + (m-1) \times (m^1 + (m-1)))}}{m^4}\]

骰子投 n 次时某一数字已出现过的概率可归纳为:

\[P_n = \frac{m^{n-1} + (m-1) \times \boldsymbol{(P_{n-1} \times m^{n-1})}}{m^n} = \frac{1 + (m-1) \times P_{n-1}}{m}\]
def P(m, n, f):
    if n == 0:
        return 0
    else:
        return (1 + (m - 1) * f(m, n - 1, f)) / m


if __name__ == '__main__':
    prob = P(6, 2, P)
    print(prob) # => 0.3055555555555556




抽卡概率问题

骰子的概率问题可以很容易就引申并推广到抽卡的概率问题,某一类可能抽到的卡就是骰子的其中一或多面, 更高的概率意味着占据了更多的面数。

规则如下:你每抽一次,更稀有的品质将提升一定的概率百分比,那么该规则即可归纳如下 —— 一个正 m 面体骰子,每骰一次其中一面就会变成更稀有的数字,然后将使用该骰子进行新一轮的投掷。

骰子投 1 次时你想要的数字已出现过的概率:

\[Q_1 = \frac{m^0}{m^1}\]

骰子投 2 次时你想要的数字已出现过的概率:

\[Q_2 = \frac{m^1 \times 2 + (m-2) \times \boldsymbol{m^0}}{m^2}\]

骰子投 3 次时你想要的数字已出现过的概率:

\[Q_3 = \frac{m^2 \times 3 + (m-3) \times \boldsymbol{(m^1 \times 2 + (m-2))}}{m^3}\]

骰子投 4 次时你想要的数字已出现过的概率:

\[Q_4 = \frac{m^3 \times 4 + (m-4) \times \boldsymbol{(m^2 \times 3 + (m-3) \times (m^1 \times 2 + (m-2)))}}{m^4}\]

骰子投 n 次时你想要的数字已出现过的概率:

\[Q_n = \frac{m^{n-1} \times n + (m-n) \times \boldsymbol{(Q_{n-1} \times m^{n-1})}}{m^n} = \frac{n + (m-n) \times Q_{n-1}}{m}\]
def Q(m, n, f, diff=0):
    if n == 0:
        return 0
    else:
        # diff 默认为 0,nt 和 diff 是为了和我下面要讲的东西做兼容
        nt = n - diff
        return (nt + (m - nt) * f(m, n - 1, f, diff)) / m


if __name__ == '__main__':
    prob = Q(6, 2, Q)
    print(prob) # => 0.4444444444444444

抽卡概率问题实际上是骰子概率问题的一个更广义版本,那么两项归纳后的公式如此相似也是意料之中。




抽卡的正确姿势?

我似乎发现了一个能够以相对少的资源抽取资深干员的高性价比抽卡策略。

首先明日方舟的抽卡概率是这样规定的: $6\bigstar$ 占标准寻访概率的 $2\%$, 如果累计寻访 50 次没有获得 $6\bigstar$ 干员,则从下一次开始每一次较上一次提高 $2\%$,即 $1 \over 50$, 也就是第 100 次出 $6\bigstar$ 的概率可以达到 $100\%$。

前 50 次就可以抽到 $6\bigstar$ 的概率可以用上面第一条公式算出, 而 50 次以后才抽到 $6\bigstar$ 的概率则可以用上面第二条公式算出。

def yjprob(m, n, f, diff):
    if n == 0:
        return 0
    if n == 100:
        return 1
    elif n <= diff:
        return P(m, n, P)
    else:
        return Q(m, n, yjprob, diff)


if __name__ == '__main__':
    # diff: 第 50 次开始概率增加
    # m: 单抽 6* 的概率为 2%,理解为一个正 50 面体的骰子的面数
    # n: 抽的总次数
    diff, m, n = 50, 50, 60
        
    prob = yjprob(m, n, None, diff)
    print(prob) # => 0.8887952002031017