幻塔【幻塔】[数据研究] 初窥幻塔抽卡机制如下:
原帖是大佬发布在NGA的攻略贴,个人在使用过程中受益颇多,申请搬运到供大家使用。不做任何商业用途,如有侵权,我会立即删除本帖。
[数据研究] 初窥幻塔抽卡机制
===引子===
最近想着看一看各个抽卡游戏的抽卡系统设计,多收集收集,并改进一下自己的工具包,看了好几个游戏的抽卡机制。
这次就来看看幻塔的抽卡机制。
===武器官方公示概率===
金核和赤核抽取SSR武器基础概率0.75%,综合概率2%(即加入80抽保底)
金核和赤核抽取SR武器基础概率1%,综合概率12%(即加入10抽保底)
SSR好说,按照每次80循环中的1-79抽时概率固定为0.75%,第80抽固定100%计算,对应综合概率为1.990625%,和公示的2%非常接近。如果把1-79抽的概率改为0.76%,则综合概率为2.0005%,说不定真实情况固定的概率是0.76%不是0.75%,只是文案想凑5的倍数。
SR就有点看不懂了,稍微看了一些主播抽卡,人工统计了一小批数据。
8 7 7 7 7 8 8 10 10 10 9 9 8 9 9 8 9 10 9 8 9 9 9 9 8 9 9 10 8 9 9 1 1 8 8 9 4 3 8 3 10 8 9 9 9 8 9 8 9 9 8 9 9 8 8 9 10 9 8 8 9 9 9 8 8 9 9 10 9 10 8 8 1 9 9 8 9 9 9 9 10 6 2 9 9 8 8 8 8 8 9 8 8 8 3 5 10 8 9 8 10 9 10 8 9 2 6 8 10 9 8 8 9 9 8 10 10 9 8 8 10 8 9 10 8 9 8 10 9 10 1 8 10 10 10 10 5 3 8 9 10 8 9 10 10 9 8 9 9 9 10 10 7 1 10 10
可以看出SR是有概率递增的,概率从第8抽开始递增。不过由于数据有限,并且大家不是很在乎SR的样子,就随便凑了凑,从第8抽开始每抽递增0.33,把综合概率凑到了11.7%,如图中橙线所示。
===采用模型===
SSR采用模型同官方公示,1-79固定0.75%,第80抽固定100%
SR采用模型稍有改动,1-7固定1%,第8抽34%,第9抽67%。
由于幻塔的抽卡机制不满足无后效性(出了SSR就重置保底),还有铸金兑换的机制,之前基于抽卡道具获取后就重置保底假设的工具就不好用了,需要专门为这个问题写一点DP才能解决问题。
但在群友的帮助下,了解到有人已经写了DP了(楼主id:immortalcow),。
看了下应该没写错,该考虑的情况都考虑到了,那我就懒得写了,稍微改写加入SR概率递增就直接拿来画图。
不过没写意志的抽取,我也懒得搞了,以后有空了再在这个基础上改改。
嘛,没有足够的抽卡记录,也只能做到这种程度了。
===其他小点===
限制意义:假设SSR已经有7个后,再抽同样的SSR返还铸金仍为2个。设SSR综合概率2%,SR综合概率12%,同时SR已经全满(此时期望定义为,当抽数趋于无穷时平均每个道具所花费的抽数。
以下在限制意义下进行讨论(实际情况下每次UP抽数是有限的,总是会比限制意义下更差)
对于SSR获取的来源来说42.51%来自80抽保底,32.3%来自120铸金兑换,25.19%来自非保底区域
对于限定SSR获取的来源来说32.13%来自80抽保底,48.84%来自120铸金兑换,19.03%来自非保底区域
限制意义下,每个SSR的期望为34抽,每个限定SSR的期望为51.406抽。这个值比实际情况所需的值低了很多,一般情况可以参考下表。(不过好像有点点小问题,晚点检查一下)
当然在这个限制意义下并不适合指导普通玩家抽卡,还是看上面的图吧。总之,不抽到120保底会很亏。
===代码===
code
[code=py]
# author immortalcow
# edit by OneBST
# GGanalysis Project
import numpy
import pandas
pandas.set_option("display.max_rows",1000)
import matplotlib
from matplotlib import pyplot as plt
# matplotlib.rcParams["font.sans-serif"]=["SimHei"]
# matplotlib.rcParams["axes.unicode_minus"]=False
#幻塔官方公布的抽卡概率数值
SSR_PROBABILITY_BASIC=0.0075
SR_PROBABILITY_BASIC=0.01
SSR_PROBABILITY_CRITICAL=0.5
SSR_INSURANCE_LIMIT=80
SR_INSURANCE_LIMIT=10
SSR_PRICE_GOLD_CAST=120
SSR_MAX_COUNT=7
#开始抽卡前的状态配置,请注意根据自身情况修改
MAX_STEPS=764 #最多抽这么多次
SSR_INSURANCE=0 #当前SSR小保底计数
SR_INSURANCE=0 #当前SR保底计数
GOLD_CAST=0 #当前已有回火铸金数
def AddOrUpdate(state,key,value):
if key in state:
state[key]+=value
else:
state[key]=value
#处理铸金到SSR取得数的转换,以及设置SSR取得数封顶以避免状态空间无限扩展
def ProcessState(ssr_count,ssr_insurance,sr_insurance,gold_cast):
if gold_cast>=SSR_PRICE_GOLD_CAST:
ssr_count+=gold_cast//SSR_PRICE_GOLD_CAST
gold_cast%=SSR_PRICE_GOLD_CAST
if ssr_count>=SSR_MAX_COUNT:#都已经抽满了还算个毛线
return (SSR_MAX_COUNT,0,0,0)
return ssr_count,ssr_insurance,sr_insurance,gold_cast
#当前状态概率分布为state,计算下一抽后的概率分布
def Transfer(state):
result={}
for (ssr_count,ssr_insurance,sr_insurance,gold_cast),probability in state.items():
if ssr_count>=SSR_MAX_COUNT:
AddOrUpdate(result,(SSR_MAX_COUNT,0,0,0),probability)
continue
ssr_insurance+=1
sr_insurance+=1
#SSR小保底,只有两种可能
if ssr_insurance>=SSR_INSURANCE_LIMIT:
AddOrUpdate(result,ProcessState(ssr_count+1,0,0,gold_cast+1),probability*SSR_PROBABILITY_CRITICAL)
AddOrUpdate(result,ProcessState(ssr_count,0,0,gold_cast+1),probability*(1-SSR_PROBABILITY_CRITICAL))
continue
#非保底出SSR的结算比SR保底优先
AddOrUpdate(result,ProcessState(ssr_count+1,ssr_insurance,0,gold_cast+1),probability*SSR_PROBABILITY_BASIC*SSR_PROBABILITY_CRITICAL)
AddOrUpdate(result,ProcessState(ssr_count,ssr_insurance,0,gold_cast+1),probability*SSR_PROBABILITY_BASIC*(1-SSR_PROBABILITY_CRITICAL))
#SR保底且未命中SSR
if sr_insurance>=SR_INSURANCE_LIMIT:
AddOrUpdate(result,ProcessState(ssr_count,ssr_insurance,0,gold_cast+2),probability*(1-SSR_PROBABILITY_BASIC))
continue
#非保底且未命中SSR
sr_rate_now = SR_PROBABILITY_BASIC
# OneBSR修正 SR加入简单的概率递增修正
if sr_insurance == 9:
sr_rate_now = 0.66+0.01
if sr_insurance == 8:
sr_rate_now = 0.33+0.01
AddOrUpdate(result,ProcessState(ssr_count,ssr_insurance,0,gold_cast+2),probability*(1-SSR_PROBABILITY_BASIC)*sr_rate_now)
AddOrUpdate(result,ProcessState(ssr_count,ssr_insurance,sr_insurance,gold_cast+1),probability*(1-SSR_PROBABILITY_BASIC)*(1-sr_rate_now))
return result
#简化概率分布,只关心SSR取得数
def GetDistribute(state):
result=[0]*(SSR_MAX_COUNT)
for (ssr_count,_,__,___),probability in state.items():
for i in range(ssr_count):
result+=probability
return result
#执行概率计算
def CalculateSteps(max_step,ssr_insurance=0,sr_insurance=0,gold_cast=0):
results=[{(0,ssr_insurance,sr_insurance,gold_cast):1}]
for _ in range(max_step):
results.append(Transfer(results[-1]))
results[-2]=GetDistribute(results[-2])
for i,j in results[-1].items():
if i[0]==0:
print(i,j)
results[-1]=GetDistribute(results[-1])
return pandas.DataFrame(results,columns=range(1,SSR_MAX_COUNT+1))
#执行概率计算并输出
final_result=CalculateSteps(MAX_STEPS,SSR_INSURANCE,SR_INSURANCE,GOLD_CAST)
# 绘图代码
from copy import deepcopy
import matplotlib.cm as cm
import numpy as np
import GGanalysis as gg
from GGanalysis.gacha_plot import quantile_function
# plt.plot(final_result[7].values)
# plt.show()
# exit()
# 抽n个物品最多使用多少抽
def get_most_pull(n):
core = 0
pull = 0
items = 0
while True:
pull += 1
core += 1
if pull % SSR_INSURANCE_LIMIT == 0 or pull % SR_INSURANCE_LIMIT == 0:
core += 1
if core >= SSR_PRICE_GOLD_CAST:
core %= SSR_PRICE_GOLD_CAST
items += 1
if items >= n:
return pull
# 构成绘图程序所需格式
ans_list = [gg.finite_dist_1D([1])]
for i in range(1, SSR_MAX_COUNT+1):
ans = deepcopy(final_result.values)
ans[1:] = ans[:-1]
dist = final_result.values - ans
dist = dist[:get_most_pull(i)+1]
# print(sum(final_result.values[get_most_pull(i):]))
dist = gg.finite_dist_1D(dist)
dist.p_normalization()
print(i, dist.exp, dist.exp/i)
ans_list.append(dist)
def Hotta_num(x):
return str(x-1)+'星'
# 幻塔限定SSR武器
Hotta_fig = quantile_function(
ans_list,
title='幻塔限定SSR武器抽取概率',
item_name='限定SSR武器',
text_head='本图中玩家SR全满破并记入铸金兑换
不保证模型准确,本图结果仅供参考
由于铸金兑换机制,谈论期望意义不大
如想大概估计抽数,请参考图示概率
此时获取一个道具最多需要110抽
此时获取七个道具最多需要764抽
计算@immortalcow
绘图@一棵平衡树',
text_tail='',
max_pull=675,
mark_func=Hotta_num,
line_colors=0.5*(cm.Blues(np.linspace(0.1, 1, SSR_MAX_COUNT+1))+cm.Greys(np.linspace(0.4, 1, SSR_MAX_COUNT+1))),
y_base_gap=25,
y2x_base=3,
mark_exp=False,
mark_max_pull=False,
is_finite=True)
Hotta_fig.show_figure(dpi=300, savefig=True)
[/code]
以上就是幻塔【幻塔】[数据研究] 初窥幻塔抽卡机制相关内容。