Python으로 나타낸 공격력 업그레이드 보너스와 DPS.
본 확장모드의 공격력 업그레이드 보너스치는 이 게시글(공격력 업그레이드 추가치 계산 공식 : 울트라리스크는 왜 +9?)에서도 이미 밝히고 있습니다만은, 이를 좀 더 명확하게하는 파이썬 코드를 보면 아래와 같다고 할 수 있습니다.
파이썬에 대해서 하나도 모르셔도 아래의 코드는 고작해야 계산기를 두들기는 것을 손질한 정도에 불과하오니 마음편히 읽어주세요.
def upgrade_bonus(damage):
counter = 1
while True:
if 10*counter - 10 < damage < 10*counter + 5:
break
else:
counter += 1
return counter
공격력 업그레이드를 완료했을 때, 그 유닛이 획득할 추가수치를 알려주는 함수입니다. 업그레이드 보너스의 원칙은 다음과 같습니다.
그래서 counter라는 변수를 1부터 증가시켜서, 반올림한 영역 안에 걸쳐들어가도록 부등식을 위와같이 설정하여 반복문이 끝나는 시점의 값을 반환시키면 원하는 결과를 얻을 수 있습니다.
def dps(initial_damage, initial_period, upgrade_level, delay_decrease=True):
if delay_decrease:
x = (initial_damage + upgrade_bonus(damage=initial_damage) * upgrade_level) * pow(1.05, upgrade_level) / initial_period
else:
upgrade_bonus_prime = round(((pow(1.05, 10) - 1) / 10) * initial_damage + pow(1.05, 10) * upgrade_bonus(damage=initial_damage), 0)
#print('rescaled upgrade bonus = ', upgrade_bonus_prime)
x = (initial_damage + upgrade_bonus_prime * upgrade_level) / initial_period
return x
이제 위의 upgrade_bonus라는 함수를 이용해서 어느 유닛의 이상적인 dps를 계산할 수 있습니다. (여기서 "이상적"이라고 한 것은, 스타크래프트2의 유닛들의 공격은 실제로는 완전히 dps대로 움직이지 않고 무작위 공격주기라고하여 0.0625초에서 0.125초의 간극의 영향을 받기때문입니다.) dps의 공식은 잘 알려져있다시피, 공격력을 그 주기로 나눈 것입니다.
만약 해병, 추적자, 바퀴같이 공격력 업그레이드에 따라서 공격주기가 감소하는 유닛이라면 상기의 식
x = (initial_damage + upgrade_bonus(damage=initial_damage) * upgrade_level) * pow(1.05, upgrade_level) / initial_period
파이썬에 대해서 하나도 모르셔도 아래의 코드는 고작해야 계산기를 두들기는 것을 손질한 정도에 불과하오니 마음편히 읽어주세요.
def upgrade_bonus(damage):
counter = 1
while True:
if 10*counter - 10 < damage < 10*counter + 5:
break
else:
counter += 1
return counter
공격력 업그레이드를 완료했을 때, 그 유닛이 획득할 추가수치를 알려주는 함수입니다. 업그레이드 보너스의 원칙은 다음과 같습니다.
- 원래 공격력을 10으로 나누어서 반올림한 값을 업그레이드 추가치로 한다.
- 만약 소수점밖에 없다면 업그레이드 추가치는 1이다.
- 한 유닛의 업그레이드 보너스는 모든 업그레이드 레벨에서 동일하다.
1을 구체적인 값을 대입하면 다음과 같습니다. 바퀴의 공격력은 16이므로, 이를 10으로 나눈 결과는 1.6입니다. 그러므로 반올림하여 업그레이드 보너스는 +2입니다. 반면에 추적자의 기본 공격력은 13이므로 10으로 나눈 결과는 1.3이므로 반올림했을 때 보너스는 +1입니다.
2는 해병에서 예시를 들면 해병의 공격력은 6이므로 이를 10으로 나누면 0.6입니다. 따라서 업그레이드 보너스는 +1입니다.
그래서 counter라는 변수를 1부터 증가시켜서, 반올림한 영역 안에 걸쳐들어가도록 부등식을 위와같이 설정하여 반복문이 끝나는 시점의 값을 반환시키면 원하는 결과를 얻을 수 있습니다.
def dps(initial_damage, initial_period, upgrade_level, delay_decrease=True):
if delay_decrease:
x = (initial_damage + upgrade_bonus(damage=initial_damage) * upgrade_level) * pow(1.05, upgrade_level) / initial_period
else:
upgrade_bonus_prime = round(((pow(1.05, 10) - 1) / 10) * initial_damage + pow(1.05, 10) * upgrade_bonus(damage=initial_damage), 0)
#print('rescaled upgrade bonus = ', upgrade_bonus_prime)
x = (initial_damage + upgrade_bonus_prime * upgrade_level) / initial_period
return x
이제 위의 upgrade_bonus라는 함수를 이용해서 어느 유닛의 이상적인 dps를 계산할 수 있습니다. (여기서 "이상적"이라고 한 것은, 스타크래프트2의 유닛들의 공격은 실제로는 완전히 dps대로 움직이지 않고 무작위 공격주기라고하여 0.0625초에서 0.125초의 간극의 영향을 받기때문입니다.) dps의 공식은 잘 알려져있다시피, 공격력을 그 주기로 나눈 것입니다.
만약 해병, 추적자, 바퀴같이 공격력 업그레이드에 따라서 공격주기가 감소하는 유닛이라면 상기의 식
x = (initial_damage + upgrade_bonus(damage=initial_damage) * upgrade_level) * pow(1.05, upgrade_level) / initial_period
에 따라서 dps를 계산할 수 있습니다. 그러나 업그레이드에 따라서 공격주기가 감소하지 않는 유닛들, 즉 맹독충, 울트라리스크 등,은 공격 주기를 1.05의 정수 지수로 나눈 값을 사용할 수 없고, 별도의 업그레이드 보너스를 사용해야합니다. 그 부분이 바로
upgrade_bonus_prime = round(((pow(1.05, 10) - 1) / 10) * initial_damage + pow(1.05, 10) * upgrade_bonus(damage=initial_damage), 0)
이 부분입니다. 이 식에 대해서 좀 더 부연설명이 필요한데, 모든 공격력, 방어력 업그레이드는 10단계까지만 수행할 수 있으므로 10단계에서의 dps가 어떤 유닛이 가질 수 있는 dps의 상한선이 됩니다. 그러니 공격주기가 전혀 감소하지 않는 유닛이 얻는 추가치는 10단계를 기준으로 계산해야합니다.
어떤 유닛의 공격력을 x, 그 보너스치를 upg(x), 공격주기를 d라고 하면 10단계에서의 dps는 아래의 식과 같습니다.
DPS = pow(1.05, 10) * (x + 10 * upg(x)) / d
이제 새로운 보너스치를 upg_2(x)라고하면 10단계에서의 dps는 아래의 식과 같습니다.
DPS = (x + 10 * upg_2(x)) / d
DPS로 표현되는 두 식은 결국
pow(1.05, 10) * (x + 10 * upg(x)) / d = (x + 10 * upg_2(x)) / d
이므로, 이를 upg_2(x)에 대해서 정리합니다.
pow(1.05, 10) * (x + 10 * upg(x)) = (x + 10 * upg_2(x))
10 * upg_2(x) = (pow(1.05, 10) - 1) * x + 10 * pow(1.05, 10) * upg(x)
∴ upg_2(x) = (pow(1.05, 10) - 1) * x / 10 + pow(1.05, 10) * upg(x)
여기에 이제 업그레이드 보너스치는 항상 자연수여야하기때문에 round함수로 반올림처리하는 나머지 작업을 한 것이 바로 위에서 볼 수 있는 upgrade_bonus_prime입니다.
실제로 함수를 사용해서 계산해보면 게임 내에서의 값과 계산이 일치함을 알 수 있습니다. 맹독충을 예로 들면, 맹독충은 20+15vs경장갑이고, 자폭 공격이므로 별도의 공격 주기가 필요없습니다. 따라서 initial_period=1, delay_decrease=False로 설정한 아래의 반복문을 사용할 수 있습니다.
for i in range(11):
Baneling_dps = dps(initial_damage=20, initial_period=1, upgrade_level=i, delay_decrease=False)
Baneling_dps_light = dps(initial_damage=15, initial_period=1, upgrade_level=i, delay_decrease=False)
Baneling_dps_structure = dps(initial_damage=80, initial_period=1, upgrade_level=i, delay_decrease=False)
print(f'Baneling net damage Upgrade Level : {i} = {Baneling_dps} + {Baneling_dps_light} = {Baneling_dps + Baneling_dps_light}, vs Structure : {Baneling_dps_structure}')
"""
Baneling net damage
Upgrade Level : 0 = 20.0 + 15.0 = 35.0, vs Structure : 80.0
Upgrade Level : 0 = 20.0 + 15.0 = 35.0, vs Structure : 80.0
Upgrade Level : 1 = 25.0 + 19.0 = 44.0, vs Structure : 98.0
Upgrade Level : 2 = 30.0 + 23.0 = 53.0, vs Structure : 116.0
Upgrade Level : 3 = 35.0 + 27.0 = 62.0, vs Structure : 134.0
Upgrade Level : 4 = 40.0 + 31.0 = 71.0, vs Structure : 152.0
Upgrade Level : 5 = 45.0 + 35.0 = 80.0, vs Structure : 170.0
Upgrade Level : 6 = 50.0 + 39.0 = 89.0, vs Structure : 188.0
Upgrade Level : 7 = 55.0 + 43.0 = 98.0, vs Structure : 206.0
Upgrade Level : 8 = 60.0 + 47.0 = 107.0, vs Structure : 224.0
Upgrade Level : 9 = 65.0 + 51.0 = 116.0, vs Structure : 242.0
Upgrade Level : 10 = 70.0 + 55.0 = 125.0, vs Structure : 260.0
"""
이를 해병에 적용하면 다음과 같습니다.
for i in range(11):
Marine_dps = dps(initial_damage=6, initial_period=0.8608, upgrade_level=i)
print(f'Marine damage and dps Upgrade Level : {i} = {6 + i} / {0.8608 / pow(1.05, i)} :: {Marine_dps}')
"""
Marine damage and dps
Upgrade Level : 0 = 6 / 0.8608 :: 6.9703
Upgrade Level : 0 = 6 / 0.8608 :: 6.9703
Upgrade Level : 1 = 7 / 0.8198 :: 8.5386
Upgrade Level : 2 = 8 / 0.7808 :: 10.2463
Upgrade Level : 3 = 9 / 0.7436 :: 12.1034
Upgrade Level : 4 = 10 / 0.7082 :: 14.1207
Upgrade Level : 5 = 11 / 0.6745 :: 16.3094
Upgrade Level : 6 = 12 / 0.64234 :: 18.6816
Upgrade Level : 7 = 13 / 0.6118 :: 21.2504
Upgrade Level : 8 = 14 / 0.5826 :: 24.0292
Upgrade Level : 9 = 15 / 0.5549 :: 27.0329
Upgrade Level : 10 = 16 / 0.5285 :: 30.2769
"""
따라서 해병은, 10단계 업그레이드 기준으로 dps가 334.37%향상되는 것과 마찬가지이며, 맹독충도 같은 방법으로 하면 250% + 266.67% / 225% 향상되는 것을 알 수 있습니다.
이런 결과를 다른 유닛에 적용해보고싶고, 그렇지만 파이썬을 설치하는 것이 번거롭다면 Google Colab을 사용할 수도 있습니다, 그렇지 않다면 손과 계산기, 아니면 자신에게 익숙한 툴로 계산할 수도 있을 것입니다.
댓글
댓글 쓰기