作者:橙汁时间:02-01浏览:
赛尔号赛尔号计算解析系列文章(第二期):单双属性克制系数计算方法与n属性计算公式猜想,由橙汁带来的浓浓学术氛围的解析攻略来啦!想要自己尝试计算属性克制关系的小赛尔们可以来看看哦~
【文章大体介绍】
本文主要是介绍单属性与双属性的克制系数计算方法,解析常见的错误的计算方法加以改正,并根据单双属性推测推广n属性的算法。
在开始正文之前,我先来回答一些大家可能会问到的一些问题,这些问题的回答或许对您阅读文章有一定帮助。
Q:这种文章岂不是把简单的问题复杂化?
A:从实践中总结经验,由特殊推广到一般,将实践经验上升为理论成果,最终还要用理论指导实践活动,并在实践中检验与发展真理。这大概就是我们所说的“辩证唯物主义认识论”吧。数学模型的提出不是将简单的问题复杂化,而是将具体的事物抽象出其本质,在更深的层面认识世界,并用以更好地改变世界。
Q:只是玩一个游戏至于这样吗?
A:对于一个游戏,是否值得花费精力对其进行更加彻底地剖析呢?或许每个人的想法不同,对于游戏,怎样去玩每个人有不同的见解。对游戏的运行机制进行分析何尝不是一种游玩游戏的方式呢?
Q:我一点儿都看不懂怎么办?我该如何阅读这篇文章?
A:由于使用了数学函数工具,所以或许对于一部分玩家阅读起来比较难以理解,不过我相信看这篇文章的小伙伴都是学霸,仔细阅读一定可以看懂的。一般玩家阅读完文章可以掌握单属性与双属性的克制系数计算方法,为了帮助大家理解,文章中除了数学表达式,也有很多文字描述,并且还有实战举例。对于数学感兴趣的小伙伴可以阅读一下n属性克制系数计算公式,这一部分比较难理解。对于编程感兴趣的小伙伴可以看一下最后的C++代码。如果你实在看不懂数学猜想和代码那些部分,你可以了解一下单双属性的计算方法。
Q:写这篇文章的目的是什么?
A:主要是为了帮助大家搞清楚单属性与双属性的克制系数的计算方法,并纠正大家常犯的错误的计算方法,帮助大家了解一些游戏运行的机制,并讲述一下关于n属性系数计算公式的猜想。
【单双属性克制系数计算方法】
接下来开始正文。首先,我们来了解一下游戏中实战的单属性与双属性克制系数计算方法。
1、单属性攻击单属性的克制系数:
查表获得,系数只能为0(无效)、0.5(微弱)、1(普通)、2(克制)这四个数。
假设攻击方单属性为A,防守方单属性为B,A攻击B的克制系数为x1 ,则对于A打B的克制系数f(1,x1),有f(1,x1)= x1 。
2、双属性攻击单属性的克制系数:
如果攻击方的两个属性打防守方单属性的两个系数都是2,那么该双属性打单属性的系数为2+2=4;
如果攻击方的两个属性打防守方单属性的两个系数中至少有一个是0,那么双属性打单属性的系数为两个系数之和÷4;
如果不是以上两种情况,即其他的情况,那么双属性打单属性的系数为两个系数之和÷2。
假设攻击方双属性为A·B,防守方单属性为C,A攻击C的克制系数为x1,B攻击C的克制系数为x2 ,则对于A·B打C的克制系数f(2,x1,x2)。
3、单属性攻击双属性的克制系数:
如果攻击方单属性属性打防守方的两个属性的两个系数都是2,那么该单属性打双属性的系数为2+2=4;
如果攻击方单属性打防守方的两个属性的两个系数中至少有一个是0,那么单属性打双属性的系数为两个系数之和÷4;
如果不是以上两种情况,即其他的情况,那么单属性打双属性的系数为两个系数之和÷2。
假设攻击方单属性为A,防守方双属性为B·C,A攻击B的克制系数为x1,A攻击C的克制系数为x2 ,则对于A打B·C的克制系数f(2,x1,x2)。
4、双属性攻击双属性的克制系数:
用攻击方的双属性打防守方的两个属性的系数加和,再÷2。
注意,不要弄反,一定要用攻击方双属性打防守方2个组成的单属性的系数之和进行计算,也就是说拆分的是防守方的两个属性。
假设攻击方单属性为A·B,防守方双属性为C·D,A·B攻击C的克制系数为f1(2,x11,x12),A·B攻击D的克制系数为f2(2,x21,x22) ,则对于A·B打C·D的克制系数g[2, f1(2,x11,x12), f2(2,x21,x22)],有g[2, f1(2,x11,x12), f2(2,x21,x22)]= [f1(2,x11,x12) + f2(2,x21,x22)] ÷ 2。
【举例说明与验证】
可能看理论公式比较抽象,不好理解,下面我们讲几个例子说明一下。
例1】计算圣灵·地面系打电·火系的克制系数。
解:经查表可知,圣灵系打电系的系数x11为2,地面系打电系的系数x12为2,圣灵系打火系的系数x21为2,地面系打火系的系数x22为2,
则圣灵·地面系打电系的系数f1(2,x11,x12)= x11 + x12 = 2+2 = 4 , 圣灵·地面系打火系的系数f2(2,x21,x22)= x21 + x22 = 2+2 = 4 ,
进而圣灵·地面系打电·火系的系数g[2, f1(2,x11,x12), f2(2,x21,x22)]= [f1(2,x11,x12) + f2(2,x21,x22)] ÷ 2 =( 4+4 ) ÷ 2 = 4。
易错点:将单属性与双属性的算法强加给双属性与双属性的算法上,错认为两个4倍会变成8倍。
例2】计算圣灵·超能系打电·火系的克制系数。
解:经查表可知,圣灵系打电系的系数x11为2,超能系打电系的系数x12为1,圣灵系打火系的系数x21为2,超能系打火系的系数x22为1,
则圣灵·超能系打电系的系数f1(2,x11,x12)= x11 + x12 = ( 2+1 )÷2 = 1.5 , 圣灵·超能系打火系的系数f2(2,x21,x22)= x21 + x22 = ( 2+1 ) ÷ 2 = 1.5,
进而圣灵·超能系打电·火系的系数g[2, f1(2,x11,x12), f2(2,x21,x22)]= [f1(2,x11,x12) + f2(2,x21,x22)] ÷ 2 =( 1.5+1.5 ) ÷ 2 = 1.5。
易错点:错将攻击方的两个属性拆分,然后用两个攻击方的单属性打防守方双属性的系数进行计算,会错误地得到结果(4+1)÷2=2.5。
下面,为了验证例2计算结果的正确性,我们进行实战测试。(感谢阿狸与逆天帮助数据测试)
测试采用的防守方的火电王和圣缪的特防都是一样的,而且攻击方的缪斯都是首回合出招打伤害,打完就刷新重测,可以保证严格控制变量,即唯一变量为属性克制系数。由于圣缪第五技能效果“攻击时造成的伤害不会出现微弱(克制关系为微弱时都变成普通)”,因此在实战中,圣缪第五技能打对方圣缪的克制系数为1,理论上打火电王的克制系数为1.5。
由于时间匆忙,于是只打了6次(12场)进行测试,当然打的越多,算平均值就越准确。以下是这12场的伤害测试结果,表格中平均值为6次平均伤害取值,理论值为由伤害计算公式计算(我是用自制的伤害计算器算的)而来的理论平均伤害值。
伤害测试 | 格劳恩斯 | 圣瞳缪斯 | 伤害倍数 |
第一次 | 611 | 395 | 1.54683544 |
第二次 | 585 | 428 | 1.36682243 |
第三次 | 547 | 379 | 1.44327177 |
第四次 | 550 | 366 | 1.50273224 |
第五次 | 598 | 374 | 1.59893048 |
第六次 | 628 | 422 | 1.48815166 |
平均值 | 586.5 | 394 | 1.48857868 |
理论值 | 595 | 397 | 1.50000000 |
做好表格,我们将数据的折线图画出来,可以看到,打火电王(1.5倍)的伤害在600左右,打圣缪(1倍)的伤害在400左右,相除得到的结果正好是1.5倍理论值。
【n属性计算公式数学猜想】
以上就是我们在游戏的实际中遇到的属性克制系数的计算问题,接下来,我们将属性个数n进行推广。
通过对n=1,2也就是单属性与双属性的算法,我做了以下的公式推广,在理论上,可以实现n属性的计算。
注意:以下内容是猜想归纳的内容,对于单双属性而言符合游戏实际规律,三属性及以上为在单双属性实际情况的基础上所做出的大胆猜想。以下内容比较难理解,没有数学功底的小伙伴可以直接放弃阅读了。
计算多属性攻击单属性或者多属性攻击单属性的系数,
最终系数 = 各个属性攻击单属性的系数之和 ÷ 属性个数 ×(1+系数中2倍系数重复的个数)÷(1+系数中0倍系数的个数)
其中重复的个数指的是:出现0次或1次,则重复的个数是0;出现2次,重复的个数是1;出现3次,重复的个数是2;以此类推。
将算法用数学表达式进行表达如下,(表达方法有很多种,以下只是其中一种算法,数学公式只是为了直接代数,对于计算机而言计算方便,不需要进行逻辑判断,因此,只要能表达上述文字描述的定义式的结果,形式如何无所谓,并且可以多种多样)。
假设多属性的属性个数为n (n∈Z),每个属性攻击单属性的系数为xi(i=1,2,..,n),则n属性攻击单属性的计算公式f(n,x1,x2,…,xn)如下,(为了突出取整函数,不使其与中括号混淆,下文中向下取整函数“y=[x]”一律写作“y=Int(x)”)。
上述公式中又是取整又是求反正切函数,可能看的眼花缭乱,其实万变不离其宗,都是在计算2倍系数重复的个数与系数中0倍系数的个数。
计算多属性攻击多属性的系数,
最终系数 = 攻击方每个多属性攻击防守方各个属性的系数之和 ÷ 防守方属性的个数
注意:加和的是攻击方多属性攻击防守方各个单属性的系数,也就是说拆分的是防守方的两个属性,不能弄反,否则会得到错误的结果。
假设防守多属性的属性个数为n (n∈Z),攻击方的属性攻击防守方各个单属性的系数为fi(n,xi1,xi2,…,xin) (i=1,2,..,n),则多属性攻击n属性的计算公式g[n, f1(n,x11,x12,…,x1n), f2(n,x21,x22,…,x2n),…, fn(n,x n1,x n2,…,xnn)]如下:
对于单属性而言,只需要查表获得系数,只有一种情况;对于双属性而言,有双2倍、其一0、其他这三种情况;那么对于三属性而言,假设每个单属性攻击无效(系数为0)的属性只有一个,那就有三2倍、双2倍一个0、双2倍无0、非双2倍一个0、其他这五种情况;之后会越来越复杂。
根据游戏的大环境与游戏公司的想法,三属性及以上或许是不会出现的。不必说算法的复杂程度,就是系数范围也比较大,影响平衡。并且,一般人能在3秒以内准确计算出单属性和双属性的克制系数,对于三属性就有点困难了。
不过我个人觉得,如果按照上面的算法,三属性还是可以出一下的。目前单属性的系数范围为[0,2],双属性的系数范围为[0.125,4],而按照以上算法的三属性的系数范围为[0.1667,6]。
【进一步举例讲解】
或许大家对这个f(n,x)表达式比较懵逼,我进一步讲解,在讲解这个式子之前,让我们来再次看一下猜想的定义式,并用例子来说明一下。
最终系数 = 各个属性攻击单属性的系数之和 ÷ 属性个数 ×(1+系数中2倍系数重复的个数)÷(1+系数中0倍系数的个数)
我们如果要想知道系数中2倍系数重复的个数,就需要知道系数中2倍系数的个数,如果系数中有0或1个2倍系数,那么系数中2倍系数重复的个数就是0;如果是系数中有2个2倍系数,那么重复的2倍系数就有1个;如果系数中有3个2倍系数,那么重复的2倍系数就有2个;……;以此类推。
n=1(单属性)或n=2(双属性)时,也就是我们所面对的真实的游戏系数。拿我们在游戏中实际的例子来说,火系打草系的克制系数为2,那最终克制系数这样算:“各个属性攻击单属性的系数之和”为2,因为就只有一个属性;“属性个数”自然是1,“(1+系数中2倍系数重复的个数)”是1;因为系数中只有一个2倍系数,所以重复的2倍系数为0个,1+0=0;“(1+系数中0倍系数的个数)”是1,系数中没有0倍系数,1+0=1;那么也就是2÷1×1÷1=2,这对于单属性显然成立。那么,对于双属性呢?火·飞行系打草系的克制系数可以这样算:火打草是2倍,飞行打草是2倍,那么“各个属性攻击单属性的系数之和”为4,2+2=4;属性有火与飞行,“属性个数”是2个;“(1+系数中2倍系数重复的个数)”是2;因为系数中有两个2倍系数,所以重复的2倍系数为1个,1+1=2;“(1+系数中0倍系数的个数)”是1,系数中没有0倍系数,1+0=1;那么也就是4÷2×2÷1=4,这也符合双属性的计算方法。
那么对于猜想的n=3及以上怎么计算呢?方法一样呦,假设让我们来算一下水·火·草系打机械系的克制系数:“各个属性攻击单属性的系数之和”为1+2+0.5=3.5,“属性个数”是3,“(1+系数中2倍系数重复的个数)”是1+0=1,“(1+系数中0倍系数的个数)”是1+0=1,那么最终系数为3.5÷3×1÷1=1.1667。
之所以我猜想的定义式是这样的,是为了保证n=1或2(即单双属性)对于这个式子是成立的,这是基础,之后才会有n=3或更多的推导。
举完例子,大家对于定义式或许有了一定的了解了,那么让我们继续看一下那个很可怕的f(n,x)吧。
让我们把代数式一一对应,分子的 对应的是“各个属性攻击单属性的系数之和”,分母的n对应的是“属性个数”,
分子的对应的是“1+系数中2倍系数重复的个数”,
分母的对应的是“1+系数中0倍系数的个数”。
前两个都好理解,关键是后两个比较长的式子比较难理解,其实,这只是计算文字所描述的内容的一种数学表达形式,并且不是唯一的。
要想知道“系数中2倍系数重复的个数”,就要先知道“系数中2倍系数的个数”,基础系数只有0,0.5,1,2这四个,因此可以用取整函数来帮忙,计算Int(xi/2),如果系数xi是2,那么这个结果就是1,否则就是0,那所有的xi都加起来求和,就能知道系数中总共有几个2倍系数。而要计算重复的2倍系数的个数,还有一个问题,如果有2倍系数,即2倍系数的个数大于等于1,那直接用2倍系数的个数-1就可以得到结果,但如果系数中没有2倍系数,也就是2倍系数的个数为0,就不能减了。
简单的话,我们可以用最大值函数来计算“系数中2倍系数重复的个数”,也就是:
那1+系数中2倍系数重复的个数=
如果我们想玩点花样的话,就可以用反正切函数。我们现在观察一下这个函数的图像。
当x<0时,-1<y<0;当x=0时,y=0;当x>0时,0<y<1。我们要把这个特性用到克制系数的个数统计上,那就需要根据系数的特点进行调整。基础系数只有0,0.5,1,2这四个,那么对于x-0.5来说,x=0时,x-0.5=-0.5,-1<2/π*arctan(x-0.5)<0,Int[2/π*arctan(x-0.5)]=-1,Int[2/π*arctan(x-0.5)]+1=0;x≠0(即x=0.5,1或2)时,x-0.5≥0,0≤2/π*arctan(x-0.5) <1,Int[2/π*arctan(x-0.5)]=0,Int[2/π*arctan(x-0.5)]+1=1。这样,我们就把0和非0分开了。1代表有,0代表无。在f(n,x)表达式中,1代表要减去,0则代表不减,这正合我们的心意。于是“1+系数中2倍系数重复的个数”就变成了我们在上文看到的形式,也就是:
那么,统计系数中0倍系数的个数也是相似的方法,我就不详细叙述了,有兴趣的小伙伴可以自己推导一下。
解决了n对1或1对n的f(n,x),那么n对n的g(n,f)就好办了,g(n,f)其实就是把那些f(n,x)都求出来,然后加和,最后再除以属性个数n就好了。
比如,在游戏中双属性克制系数的计算,电·火系打圣灵·地面系的系数g=(f1+f2)/2=0.375。其中电·火系打圣灵的系数f1=(0.5+0.5)/2=0.5,电·火系打地面的系数f2=(0+1)/4=0.25。
再举个猜想的三属性的例子,假设需要根据以上公式计算混沌·神灵·轮回系打圣灵·自然系的系数。混沌·神灵·轮回系打圣灵系的系数f1=(1+1+2)/3×1/1=4/3,混沌·神灵·轮回系打自然系的系数f2=(2+1+0.5)/3×1/1=7/6,则混沌·神灵·轮回系打圣灵·自然系的克制系数g=(f1+f2)/2=15/12=1.25。
都说数学是最烧脑的,能坚持把这些都看完的小伙伴,我表示很佩服,估计大多数人的想法都是“太长,不看”。
【代码计算n属性克制系数】
最后又到了写代码的时间咯,以下是我写的n属性攻击单属性的克制系数计算代码。
用了两种方法,一种是根据文字描述而计算的定义法,一种是利用数学表达式直接计算的公式法。
布尔值mathWay为True则采用公式法进行计算,为False则采用定义法计算。
所用语言为C++,软件是Microsoft Visual Studio。