10分钟学会屠龙刀强化计算

发表于2016-09-09
评论17 1.79w浏览

10分钟学会屠龙刀强化计算

2016/9/9

1.    前言

必须在开篇解释一下,工具是服务于设计目标的,

写作本篇的目的,只是希望能帮大家节约工作时间,减少计算量,而并非鼓吹工具的重要性(但如果有同学因此喜欢上mathematica,我还是很高兴的);后续将整理一些常用概率、统计公式或是其它可被数值设计工作使用的基础知识。

2.   问题

某游戏有一种稀有武器——屠龙刀,屠龙刀可以强化到10(初始1),对应的强化规则如下:

等级

成功等级

失败等级

成功概率

失败概率

12

1

2

1

0.7

0.3

23

2

3

1

0.6

0.4

34

3

4

1

0.5

0.5

45

4

5

2

0.4

0.6

56

5

6

3

0.3

0.7

67

6

7

4

0.25

0.75

78

7

8

5

0.2

0.8

89

8

9

6

0.15

0.85

910

9

10

7

0.1

0.9

求得到一把+10的屠龙刀所需的强化次数

3.   背景

这个问题,涉及到随机过程——马可夫过程的计算,步骤较复杂,容易出错。相对于这个计算和学习的成本,其应用场景又较单一,一般仅用于装备强化或是占星猎命。

但这个问题又必须有一个解决的方法,无论是用于面试还是满足项目的实际需求。通常,大部分数值策划,会选择编写VBA进行模拟运算,少部分人使用excel矩阵运算。前者通常不便于复用(少部分vba达人可以写出较通用的代码),后者要求具备一定的数学功底。

于是,我推荐大家使用mathematica来解决这个问题。解答步骤仅3步,完整解答如下(详细步骤及解释见下文)

4.   解答步骤

 

STEP1:

列出状态转移矩阵:

·    第一行的1~10代表抵达状态,第一列的1~10代表出发状态

·    如图第2行第3列的值0.7,表示的是:从状态1状态2的概率是0.7(强化成功事件),状态1状态1的概率是0.3(强化失败事件)

·    保证每一行的概率之和为1

·    该矩阵表示每次强化只有成功和失败退回到指定等级这2种事件,可自行定义升级暴击等事件(有很小几率从1升到3之类)

STEP2:

Mathematica中读取表格数据:

xlsxPath= "C:\Users\Administrator\Desktop\屠龙刀强化.xlsx";

m =Import[xlsxPath, "Data"][[1]][[16 ;; 25, 2 ;; 11]]

·    第一行指定excel文档的路径

·    第二行从指定excel读取数据16;;25表示16~252;;11表示2~11(这是直接读取xlsx文件的写法若使用mathematica link for excel加载宏,可以使用Excel[“A1:C1”]这种更好理解的语法)

·    Mathemaitca读取表格数据截图:

STEP3:

定义一个马尔科夫过程:

markovProcess = DiscreteMarkovProcess[1,m];

·    DiscreteMarkovProcess(Mathematica内置的离散马科夫过程函数),接收2个参数:初始状态和状态转移矩阵

·    赋值这个离散马科夫过程到变量markovProcess

·    一句话的计算:

Mean[FirstPassageTimeDistribution[markovProcess,10]]

Mean用于计算分布的期望值

FirstPassageTimeDistribution是求首次通过指定状态的时间分布的函数,接受2个参数:马可夫过程和最终状态(这里的最终状态是10,

计算如下:

也可以求出在各状态的停留次数(1~9)

5.    问题推广:

在定义了马可夫过程之后,也可以进行模拟,如图模拟了10个分别强化10次的过程:

可以统计一下1000把屠龙刀分别强化10次后停留等级的分布:

也可以计算100次强化到+10的概率:

还可以计算每个等级不同的花费下,强化到+10的总费用,或是指定总费用,到达各等级的分布等等,有兴趣的同学可以自行研究。

昨天vba跑了3000次8w7,6000次早上看了是8w8,误差在5%,在这个样本数量下是可以接受的(但是仍无法令人满意)。

话说回来,vba的随机算法,不一定就可信。早上在python下面跑了一下,1000次是83909,另外用数组替代每个循环里重复的读取单元格的数值,效率高出好几倍。
附上python代码(ver2.76)
import random
p=[70,60,50,40,30,25,20,15,10]
lv2=[1,1,1,2,3,4,5,6,7,10]
total=0
for i in range(10000):
    lv=1
    trycount=0
    while lv<10:
        if random.randint(1,100)<=p[lv-1]:
            lv+=1
            trycount+=1
        else:
           lv=lv2[lv-1]
           trycount+=1
    total+=trycount 
print total/10000

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

17个评论

  • 猪猪 2016-09-09 1楼
    写论文呢?直接VBA走起~不能复用就以后再写~或者写个通用的,参数全体提取出来
  • 依紫韵 2016-09-09 2楼
    学习了,谢谢楼主
  • 早安 2016-09-09 3楼
    楼主大大,如果数学计算怎么算?比如,如果面试问我1级屠龙刀升到4级要强化多少次?
  • 执行者No.II 2016-09-09 4楼
    屠龙宝刀 点击就送
  • 萝卜如此风骚 2016-09-14 5楼
    这软件比MATLAB要方便啊
  • 萝卜如此风骚 2016-09-14 6楼
    其实只用excel本身,连VBA都不用也可以算出来……
  • 狂奔的小蜗牛 2016-09-18 7楼
    如图第2行第3列的值0.7,表示的是:从状态1→状态2的概率是0.7(强化成功事件),状态1→状态2的概率是0.3(强化失败事件)  //这里不是0.6么~
  • 遊戲即吾命 2016-09-18 8楼
    Public Sub 求强化到加10期望()Dim i, j, k, n As IntegerDim NowLevel, TryCount, TotalCountFor n = 1 To 100    NowLevel = 1    TryCount = 0    Do While NowLevel &lt; 10        If Rnd &lt;= Range("J9").Offset(NowLevel - 1, 0).Value Then            NowLevel = Range("H9").Offset(NowLevel - 1, 0).Value            TryCount = TryCount + 1        Else            NowLevel = Range("I9").Offset(NowLevel - 1, 0).Value            TryCount = TryCount + 1        End If    Loop        TotalCount = TotalCount + TryCount    Debug.Print n &amp; "-" &amp; TryCountNext nDebug.Print TotalCount / 100End Sub 用VBA模拟之后,发现结果是9W多阿……楼主你是不是算错了……这么多天了,难道大家都没发现么……
  • 遊戲即吾命 2016-09-18 9楼
    蒙特卡洛100次是因为想快速出结果,偷了一下懒。我又重新算了一次,还是9W多,100次样本虽小,但是不至于误差有1W这么多吧?另外注意对齐一下表格位置 难得见到有同样对技术有研究的策划,甚是感动,不论谁对谁错,都是好样的
  • 遊戲即吾命 2016-09-18 10楼
    不可能你的RND和我的RND不一样吧?
  • 遊戲即吾命 2016-09-18 11楼
    http://www.gameres.com/forum.php?mod=viewthread&amp;tid=681282&amp;extra=page%3D1&amp;from=portal&amp;page=1 另外可以看下游资网那边的评论,大家用VBA算出来都是9W多
  • 遊戲即吾命 2016-09-19 12楼
    如果再加一个暴击后强化等级+2的分支,vba又将如何处理? 这个很好处理阿,因为VBA靠的就是模拟实际情况而非计算
  • 蓝海 2016-09-20 13楼
    干货,感谢分享
  • 破戒僧 2016-09-20 14楼
    python下用了一上午模拟了100000次,平均强化次数为83030,后续不会再行尝试了。
  • 曹操 2017-02-13 15楼
    首先给楼主点个赞,不容易。其次,excel真的可以很简单的有一个函数算出来的,大致思路是:从N强化到N+1的单次强化成本=1/成功率  +  1/失败率  ×  (vlookup“N级”对应的累计强化成本  -  vlookup“失败后的等级”对应的累计强化成本)//假设每次强化不是消耗1个材料,而是M个材料,则把分子上的1替换成M。