一、概率增量
这部分内容在前面讲解过,这里直接上代码
# _*_ coding: utf-8 _*_
# @Author : ******
# @Time : 2022/8/24 9:48
# @File : PseudoRandomDistribution.py
# @Project: TestCase
import math
class PRD:
def __init__(self):
# 环境
self.env = None
# 精度
self.precision = 0.0000000000001
def log_out(self, content):
if "DEBUG" == self.env:
print(content)
def sum_arithmetic_sequence(self, N):
"""
等差数列前N项求和
:param N:第N项
:return:和
"""
res = 0
for i in range(N + 1):
res += i
return res
def get_avgp_by_c(self, c):
"""
通过c求得Nmax次操作中的平均概率
:param c:概率增量
:return:平均概率
"""
# 初始化变量
p_sum_pre_success = 0
p_sum = 0
# 计算c值对应的最大操作次数
Nmax = math.ceil(1 / c)
self.log_out(f"--当前[ c: {c}, Nmax: {Nmax} ]")
for i in range(1, Nmax + 1):
p_curr = min(1, i * c) * (1 - p_sum_pre_success)
p_sum_pre_success += p_curr
p_sum += i * p_curr
self.log_out(f"{i}: [sum_pre_success_p: {p_sum_pre_success}, curr_p: {p_curr}, sum_p: {p_sum}")
p_avg = 1 / p_sum
self.log_out(f"--p_avg: {p_avg}\n#")
return p_avg
def get_c_by_p(self, p):
"""
通过已知触发某项操作的概率求得概率增量
e.g.已知暴击率为50%,求概率增量c
:param p:触发某项操作的概率
:return:概率增量
"""
min_ = 0
max_ = p
while True:
mid_ = (min_ + max_) / 2
p_avg = self.get_avgp_by_c(mid_)
if abs(p_avg - p) < self.precision:
self.log_out(f"--FINAL C: {mid_}")
return mid_
if p_avg > p:
max_ = mid_
else:
min_ = mid_
二、模拟攻击操作
# _*_ coding: utf-8 _*_
# @Author : ******
# @Time : 2022/8/25 10:07
# @File : AnalogTrigger.py
# @Project: TestCase
import math
import random
from game_prob.PseudoRandomDistribution import PRD
class AT:
def __init__(self, prob):
# 触发某项事件的概率
self.prob = prob
def get_random(self, min_, max_):
"""
在给定区间内取值
:param min_:区间最小值
:param max_:区间最大值
:return:区间值
"""
if min_ == max_: return min_
num_ = random.random() * (max_ - min_ + 1) + min_
num_ = int(num_)
return num_
def is_trigger(self,min_, max_, prob):
"""
判定本次随机是否触发事件
:param min_:区间最小值
:param max_:区间最大值
:param prob:触发事件所需概率
:return:是否触发
"""
num_random = self.get_random(min_, max_)
return num_random <= prob, num_random
def simulation(self):
pdr = PRD()
pdr.env = "Release"
# 获取概率增量
c = pdr.get_c_by_p(self.prob)
# 获取最大操作次数
Nmax = math.ceil(1 / c)
# 观察Nmax次攻击内暴击情况
N = 1
for i in range(1, Nmax + 1):
p_curr = N * c
flag, num_random = self.is_trigger(1, 100, p_curr * 100)
if flag: # 触发暴击后,N重置为1
N = 1
print(f"第{i}次攻击: [暴击概率: {p_curr}, 程序随机: {num_random / 100}, 是否触发暴击: {flag}]")
N += 1
if __name__ == '__main__':
# 触发暴击的概率为50%
prop = 0.4
# 模拟攻击
at = AT(prop)
# 启动模拟
at.simulation()
三、日志输出
第1次攻击: [暴击概率: 0.20154741360784098, 程序随机: 0.38, 是否触发暴击: False]
第2次攻击: [暴击概率: 0.40309482721568196, 程序随机: 0.05, 是否触发暴击: True]
第3次攻击: [暴击概率: 0.40309482721568196, 程序随机: 0.05, 是否触发暴击: True]
第4次攻击: [暴击概率: 0.40309482721568196, 程序随机: 0.95, 是否触发暴击: False]
第5次攻击: [暴击概率: 0.6046422408235229, 程序随机: 0.04, 是否触发暴击: True]
这里只是模拟Nmax次操作中的攻击情况