宝箱爆出装备的概率计算

⌚Time: 2024-10-16 22:37:00

👨‍💻Author: Jack Ge

宝箱是可能爆出多种装备,爆出装备可以是两种情况。一种是每个装备的概率独立。不知道最后会出现多少种装备。另一种是会并且只会爆出一种装备,哪种装备取决于各种装备的概率比例。所以就用到两种类型的概率。一个是直接给定事件发生概率,预测事件是否发生。另一种是给定一组事件各自的概率,根据他们的概率大小比例,预测发生了哪件事。

下面的是这两种概率预测的实现。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;
        }
    }