任务背景

游戏中的武器有如下属性:

  • min_dmg,最小伤害值
  • max_dmg,最大伤害值
  • timecost,每次攻击消耗的时间(越少攻击速度越快)

为了理解不同属性武器的实战效果,我们需要引入TTK(Time To Kill)这个概念,给定怪物的当前生命值 hp,函数ttk()返回使用武器击倒敌人所需时间的期望。

1
def ttk(min_dmg: int,. max_dmg: int, hp: int, timecost: float): ...

可选方法

朴素的公式

高效但有时很不精确的方法,未考虑伤害溢出以及伤害随机性。

1
2
3
def ttk_wrong(min_dmg: int, max_dmg: int, hp: int, timecost: float = 1.0):
avg_dmg = (min_dmg + max_dmg) / 2.0
return hp / avg_dmg * timecost

动态规划

理论上是精确的,但复杂度偏高。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def ttk_analytical(min_dmg: int, max_dmg: int, hp: int, timecost: float = 1.0):
E = [0.0] * (hp + 1)
dmg_range = list(range(min_dmg, max_dmg + 1))
N = len(dmg_range)

for h in range(1, hp + 1):
expected_hits = 1.0
sum_next = 0.0
for dmg in dmg_range:
next_hp = max(0, h - dmg)
sum_next += E[next_hp]
expected_hits += sum_next / N
E[h] = expected_hits
return E[hp] * timecost

蒙特卡洛

模拟次数较大时趋近于准确值,用来验证上述算法的实际偏差。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def ttk_montecarlo(min_dmg: int, max_dmg: int, hp: int, timecost: float = 1.0):
import random
rand = random.Random(42)
total_hits = 0.0
trials = 200000

for _ in range(trials):
current_hp = hp
hits = 0
while current_hp > 0:
dmg = rand.randint(min_dmg, max_dmg)
current_hp -= dmg
hits += 1
total_hits += hits

return total_hits / trials * timecost

三种方法对比

1
2
3
4
5
6
7
8
min_dmg = 3
max_dmg = 8
timecost = 1.0
hp = 10

print("TTK (Wrong):", ttk_wrong(min_dmg, max_dmg, hp, timecost))
print("TTK (Analytical):", ttk_analytical(min_dmg, max_dmg, hp, timecost))
print("TTK (Monte Carlo):", ttk_montecarlo(min_dmg, max_dmg, hp, timecost))

输出:

  • TTK (Wrong): 1.8181818181818181
  • TTK (Analytical): 2.2824074074074074
  • TTK (Monte Carlo): 2.28284