最近编写一个模拟游戏抽奖的程序,需要使用到标准库random模块,但是使用的时候出现了一个很大的问题,游戏中的抽奖概率是2.23%,是一个二位小数,并带有百分号,化成小数是0.0223,也就是说一万次抽奖中约有223次抽中,如果把所有的抽奖结果放进一个列表并用random.choice函数的话,那需要一万项,其中223项为目标结果,这样对于程序员来说工作量实在太大,所以应该编写一个对每个事件制定一个概率,让程序按照概率进行抽奖的函数。
在这里给大家推荐一个比较好的方法,可以实现每个事件有对应的出现概率:
注:在代码块中events是所有可能出现的事件的列表,values是每个事件的概率的列表,和events一一对应,points是所有点的列表,num则是挨个检查是否符合事件的一个不起眼的变量。
from random import *
def sampling(dictionary):
#本函数的原理是代数化的几何概率
'''按照参数所指定的概率随机抽取一个元素,传入的参数始终是一个字典
其中键为事件,值为事件发生的概率,所有的值必须是介于0和1的浮点数
且所有值的和应为1,若不是这样,则抛出异常。
不支持无法化为有限小数的分数'''
events=[]
values=[]
for i in dictionary:
events.append(i)#将事件从字典中分离出来,因为dictionary.keys()返回的不是一个列表
values.append(dictionary[i])#将每个事件的概率也分离出来,与事件一一对应
if sum(values)!=1:#如果概率加起来并不是1,则抛出异常
raise ValueError('All values must be float numbers between 0 and 1 and the sum of all values should be 1.')
points=[]
for i in values:
point=0
a=values.index(i)
while a>=0:#下面将参数中提供的每个事件的概率转换为一个个类似数轴上的点
point+=values[a]
a-=1
points.append(point)
points.insert(0,0)#把数轴原点0也加入列表
#假设在数轴上,第一个点是0,第一个点和第二个点的距离是第一个事件的概率
#第二个点到第三个点的距离是第二个事件的概率,所以第三个点在数轴上的值是前两个事件概率的和,以此类推
result=random()#在0到1之间选取一个数
for num in points:
if num<=result<points[points.index(num)+1]:#这里必须是小于等于和小于,这样保证不会正好抽到1引发特殊情况而产生异常
return events[points.index(num)]#从events中获取result所在区间对应的事件
试了一下,效果还可以,适合多种事件,只要不是容易产生浮点数误差的无限循环小数就不会有问题,对于三分之一这种概率还是不支持的,像这种情况,如果是等可能事件,使用random.choice还是可以的。
本文为作者原创,转载请注明出处。
本文介绍了一种基于概率的游戏抽奖算法,通过将事件概率转化为数轴上的点,实现了精确的随机事件选择,适用于各种游戏场景。
2974

被折叠的 条评论
为什么被折叠?



