数值碎碎念(五)——从强化到技能
重新读了一遍自己写的这堆东西,貌似一直在讲方法论的东西,非常惭愧= =
所以这次讨论一点干货吧。
先从强化开始,之后我们再说为什么会从这里扯到技能上。
假设一种情况:对某装备进行强化,可能产生三种后果:掉级,不变,升级;;这里我们设计时一般会关注几个点:期望次数,经过N次强化行为后玩家处于某个特定状态的概率,还有期望成本。
简单做法
期望次数有个简单的做法:
假设现在强化等级是n(n>0),强化成功的期望次数是E(n),强化行为之后,强化等级可能掉级变成0,1,……n-1,n,n+1,概率分别记为P(n_0), P(n_1),……P(n_n-1), P(n_n), P(n_n+1);
那么,由期望的性质,我们可以列出这个方程:
E(n)=P(n_n+1)*1+P(n_n)*(E(n)+1)+P(n_n-1)*(E(n)+E(n-1)+1)+……
对于绝大多数情形,强化等级不会特别高,而且我们通常不会让装备失败就掉落底层,也就是说大多数情况下可能从第四项开始就都是0了,因此对于绝大多数强化的情况,设计时可以停在这一步,然后把E(n)当做方程来解就可以了,而且这个还可以直接在Excel写成公式下拉直接得到结论,很便捷;
不过显然我花了这么多时间来输入如此多的字母并不是想停在这里的,而是想得到一个更普适的结论。
我们记S(n)为从强化0到强化n+1的总次数
则有S(n)=E(n)+E(n-1)+……E(1),因此E(n)=S(n)-S(n-1)
然后代入并化简可得
S(n)=1/(p(n_n+1))*(1+S(n-1))-Σ(i=2 to n)(P(n_i)*S(i-1)),n>0
这样,我们就有了一个普适的公式,然后直接写个VBA或者Matlab就能运用到所有情况了。
状态矩阵的构造
上面的办法运用了期望的数学性质,所以相对简单;如果不是这样的话,我们可能需要运用到矩阵。
对于一个游戏来说,强化显然是有上限的,设这个上限为N,为了方便写下标,我们不考虑强化=0的情况直接从1开始(对,我就是这么懒)。
对于强化为m的状态来说,进行一次强化行为,可能变成强化1~N的几率分别为Pm_1~Pm_N,假设记为Pm=[Pm_1 Pm_2 …… Pm_N];
这样我们把所有强化状态都列出来,就能构造出一个N*N的矩阵了,这个矩阵的第m行表示对强化为m的状态来说,进行一次强化行为,可能变成强化1~N的几率;第m列表示强化1~N的装备进行一次强化行为,可能变成强化m的几率。
参照矩阵乘法第x行第y列的计算方式,很容易知道:如果初始状态是x,进行k次强化后达到状态y的几率,其实就是把这个矩阵与自身相乘k次,然后第x行y列对应的元素值。
于是,对于任意初始状态,强化N次后停留在每个状态的几率就这样直接解出来了……
一个显而易见的解法
显然N次以内玩家达到某个特定状态的概率也很容易求了:
设P(n-1),Pn,P(n+1)对应掉1级、不变、升1级三个状态,为了讨论方便假定只有这三个等级(更多情况同理,只是矩阵变大了。)
首先把所有状态都列出来
列出一步转移概率矩阵:
n-1 | n | n+1 | |
n-1 | 1-P(n-1_n) | P(n-1_n) | 0 |
n | P(n_n-1) | P(n_n) | P(n_n+1) |
n+1 | 0 | P(n+1_n) | 1-P(n+1_n) |
因为求的是k次以内强化到n+1的几率,所以强化到n+1就不用再变化了,所以令初始矩阵等于
n-1 | n | n+1 | |
n-1 | 1-P(n-1_n) | P(n-1_n) | 0 |
n | P(n_n-1) | P(n_n) | P(n_n+1) |
n+1 | 0 | 0 | 1 |
然后让这个矩阵取自身的k次幂即可,同样的第x行第y列就是经k次强化行为以后,初始状态由x变为y的概率。
显然,k次强化后的概率矩阵取初始状态行点乘等级向量就是经过k次强化后的期望等级了。
由状态转换矩阵求期望
我们已经知道状态转换矩阵的n次幂就代表结果,那么期望怎么用矩阵求呢?
其实跟上面的办法很接近,只不过在上一个问题中我们设定“强化k次或达到强化n+1”停止,这里的条件就是“达到n+1”。
用矩阵来解确实麻烦一些,尤其与第一段“简单做法”比起来。不过办法还是有的。
如果我们假设强化到目标等级总共需要k次的话,也就意味着前面k-1次都未达到目标等级;
我们假设求的从x强化到y,设状态矩阵为P,那么就得构造一个矩阵P’,P’的第Y列=0,然后P’^(k-1)*P就是最终的状态矩阵,其中第x行第y列元素就是“从x强到y共强化k次”这一事件发生的概率。
为了数学上方便,E为单位矩阵的话,Ey就是令单位矩阵的第y列=0;同理Ix设为1行n列的向量,第x个元素为1其余均为0、Iy为n行1列的向量,第y个元素为1其余均为0。
这样,从x强到y共强化k次的概率就可以用数学语言表示为:Ix*(PEy)^(k-1)*P*Iy
那么,期望次数就相当于上述概率乘以k,然后令k=1到无穷大求和了;
期望次数用Exy来表示的话,就有Exy=Σ(k=1 to ∞)(k* Ix*(P*Ey)^(k-1)*P*Iy)
当k趋近于无穷大时,有Exy=Ix*(E-P*Ey)^(-2)*P*Iy;
多说一句结论,如果每个等级对应的消耗不一样的话,用成本矩阵点乘各个等级的期望次数可以得到消耗矩阵,设成本矩阵是c,x到y的总消耗是Cxy,直接说结论:Cxy=c·(Ix*((E-P*Ey)^(-1)*P+E)*Ey)
扯远点到战斗
说到底,这玩意跟战斗有啥关系?
我们先回想一下上一篇碎碎念中提到的,我们设计时需要假设的玩家状态,这个是设计的第一步;但是到第二步,也就是实际设计技能数值时会发现,一个技能造成的可能状态不止一个,常见的:眩晕技有可能让玩家进入眩晕,也有可能直接造成死亡;还有一些类似蓄力的技能,可能随着蓄力时间的改变,其效果也会有所变化;那么,这个技能的消耗、cd和伤害值要怎么做呢?
假设一个技能,可能需要预判对手行为,玩家预判的准确度我们可能通过各种手段和经验得到一个预期值(不一定准,但是后续可能会统计玩家数据进行调整,典型的例子是Dota里月之女祭司的箭和屠夫的钩,前期版本调整过无数次,原因就是需要不断根据玩家平均水平设定,当然绝大多数指向性技能命中率就是100%,有些技能的命中率也是非常容易估准,所以我们看到骷髅王和流浪剑客的锤子都基本没怎么改过);通过这个预期值,我们可以构造一个状态转移矩阵,根据伤害可以计算出这个技能直接致死的概率;然后把眩晕作为,进而统计出我们想要的、关于这个技能的收益,或者根据收益逆推成本。
那为什么不一开始就用技能举例呢?一方面,讨论强化相关的文章比较多,参考起来比较方便,反正我的最终目的是引出状态转移矩阵基于这个状态转移矩阵的计算方法,至于这个方法能应用在哪些方面都是看自己的需求,用来买彩票也是可以的;另一方面,讨论强化从x到y多简单啊,直接用Exy就能表示了,“从正常状态到眩晕和从正常状态到死亡状态……”这种说法,太绕口了吧=_=当然,最主要的原因还是,我就爱这么胡扯啊^_^
所以最后还是写成了一篇包裹在“干货”外衣下的方法论,唉,人生不如意十之八九啊……