宝箱是可能爆出多种装备,爆出装备可以是两种情况。一种是每个装备的概率独立。不知道最后会出现多少种装备。另一种是会并且只会爆出一种装备,哪种装备取决于各种装备的概率比例。所以就用到两种类型的概率。一个是直接给定事件发生概率,预测事件是否发生。另一种是给定一组事件各自的概率,根据他们的概率大小比例,预测发生了哪件事。
下面的是这两种概率预测的实现。g_RandomGenerator是一个设置好随机数种子的mt19937 随机数生成器。
//根据概率预测随机事件是否发生
bool Tool::did_this_event_occur(float probability){
if(probability<0||probability>1){
std::cerr<<"Invalid event:event probability must between 0 and 1\n";
return false;
}
//伯努利分布是一种最简单的二元概率分布,它描述了一个试验只有两种可能结果(成功或失败)的情况
std::bernoulli_distribution distribution(probability);// 概率
//模拟事件发生
bool eventOccurred = distribution(g_RandomGenerator);
//返回结果
return eventOccurred;
}
//一组具有各自概率的事情,只会发生一件事情,预测哪件事会发生
int Tool::which_thing_happened(float probabilityList[],int thingsNumber){
//总概率
float totalProbability = 0.f;
for(int i=0;i<thingsNumber;i++){
totalProbability += probabilityList[i];
}
//产生随机数,从0到总概率大小
std::uniform_real_distribution<float> floatDistribution(0.f,totalProbability);
//产生的随机数位置就是发生的事件所在的概率位置
float happenedPosition = floatDistribution(g_RandomGenerator);
//计算随机数的位置对应的事件。
float currentPosition = 0.f;
int result = 0;
for(;result<thingsNumber;result++){
currentPosition += probabilityList[result];
if(currentPosition>=happenedPosition){
break;
}
}
//返回是第几件事情发生
return result;
}这是宝箱信息结构体。
//最后得到的奖励物品结构体 用于返回信息
typedef struct BonusItemList{
int ItemNumber;
struct{
char ItemName[MAX_NAME_LENGTH];//装备名字
int ItemNumber;//装备数量
}Items[5];
}BonusItemList;
//宝箱奖励物品信息
typedef struct BoxItemBonusInfo{
int BoxItemNumber;
struct{
//装备名字和数量
char ItemName[MAX_NAME_LENGTH];
int ItemNumber;
//概率
float ItemProbability;
}ItemInfos[5];
//影响计算得到物品的方式
//如果是真,那些奖励物是独立的概率计算,是否获得每个物品取决于各自的概率。
//如果是假。就是必定获得一件物品,得到什么物品的概率比例是物品各自概率的比例
bool IsIndependentProbability;
}BoxItemBonusInfo;
这是宝箱爆装备的函数。执行它就会得到爆出的装备列表了。其中m_bBonusHasBeenTaken用于标记宝箱是否被打开过了。
//获取物品奖励 返回值代表获取成功和失败
bool take_bonus(BonusItemList &itemList){
if(m_bBonusHasBeenTaken){
return false;
}else{
//清空结构体
memset(&itemList,0,sizeof(itemList));
//根据类型开始爆装备
if(m_itemBonusInfo.IsIndependentProbability){
//可能爆多种装备
itemList.ItemNumber = 0;
for(int i=0;i<m_itemBonusInfo.BoxItemNumber;i++){
//根据概率发生
if(Tool::did_this_event_occur(m_itemBonusInfo.ItemInfos[i].ItemProbability)){
strcpy_s(itemList.Items[itemList.ItemNumber].ItemName,m_itemBonusInfo.ItemInfos[i].ItemName);
itemList.Items[itemList.ItemNumber].ItemNumber = m_itemBonusInfo.ItemInfos[i].ItemNumber;
itemList.ItemNumber++;
}
}
}else{
//只会爆一种装备
//分配空间
float *probabilityList = new float[m_itemBonusInfo.BoxItemNumber];
//获取概率列表
for(int i=0;i<m_itemBonusInfo.BoxItemNumber;i++){
probabilityList[i] = m_itemBonusInfo.ItemInfos[i].ItemProbability;
}
//预测哪种装备爆出
int happenedItemIndex = Tool::which_thing_happened(probabilityList,m_itemBonusInfo.BoxItemNumber);
//释放空间
delete []probabilityList;
//返回结果
itemList.ItemNumber = 1;
strcpy_s(itemList.Items[0].ItemName,m_itemBonusInfo.ItemInfos[happenedItemIndex].ItemName);
itemList.Items[0].ItemNumber = m_itemBonusInfo.ItemInfos[happenedItemIndex].ItemNumber;
}
m_bBonusHasBeenTaken = true;
return true;
}
}