原神游戏常驻池抽卡模型推测

原神常驻池抽卡模型推测


相信大家玩抽卡或者氪金类游戏时或多或少对概率有一定了解,毕竟事关到出货,如果想了解其中抽卡的奥秘,但是又无法获得源码的情况下,可以通过推测模型去试图接近原本游戏的设计。当然这个推测只是力求在数据结果上去接近,或许游戏的实际源码和本文中贴出的有非常大的出入,并且个人编程水平不高,所以本文主要面向菜鸟和新手,也欢迎相关专业人士指正。如果是为了寻找关于抽卡的高深学问,请直接跳过本文以免浪费您宝贵的时间。

以最近比较火的游戏《原神》举例,先从简单情况入手。
首先看常驻池的说明,截图时间为2021-03-02(由于图片太长影响观感,完整的图在后面放出,部分数据在长图上有,如果对游戏感兴趣也可以登录游戏直接查看)
常驻祈愿详细信息

从中可以得知关键信息为:

5星基础:0.6%,5星角色:0.3%, 5星武器:0.3%
5星保底:1.6%,90抽5星保底
5星角色数量:5, 5星武器数量:10 (附图的长图中)

4星基础:5.1%,4星角色:2.55%,4星武器:2.55%
4星保底:13%,10抽4星以上保底,其中4星占99.4%,5星占0.6%
4星角色数量:16,4星武器数量:18 (附图的长图中)

3星基础94.3%,保底85.4%,3星武器数量:34(附图的长图中)

1 基础概率分析和处理

1.1 处理基础概率

原图中百分比的尾数精确到了0.001%,也就是1/100000,最直接暴力的方法就是从1~100000随机取数,已知5星基础概率为0.6%,4星基础为5.1%,3星基础为94.3%,方法如下:

随机生成范围在1~100000内的随机数,按照基础概率划分区间
5星:1~600,4星:601~5700,3星:5701~100000
*注:由于从0开始计数,实际代码中的范围为0~599,600~5699,5700~99999

按照以上范围随机则可以控制基础概率。

1.2 处理角色武器平分的概率

5星角色和5星武器,4星角色和4星武器,其基础概率是相同的,平分5星和4星物品的基础概率,处理方法如下:

随机选中5星或者4星物品时,再二次随机,从0~1取值,选中0为角色1为武器或者反过来。

1.3 处理角色武器数量不等的情况

5星角色数量为5,武器数量为10,4星角色数量为16,武器数量为18,处理方法如下:

在二次随机的情况下,选中角色或者武器后,再对角色或者武器数量进行第三次随机。

2 保底机制分析和处理

10次祈愿必会获得至少1个4星或者以上物品

当有保底机制出现的时候,则基本上都会关联到一个类似水位值(或者叫幸运值)相关的东西,也就是说,不论是多么非酋的情况下,抽10次一定会获得至少一个4星或者以上的物品。此外,当前获得4星或以上物品,不一定是要距离上次出货10次后才能出现,也可能是1~6次,7次,8次,9次都可能,最非酋的情况下是10次,而决定这个可能性大小的,就是这个水位值对应的概率,用下图举例:
水位值示例1
由上图可知,当位于第8抽时候,获得高级物品的概率迅速增长。通过一定的处理后(诸如压缩其概率的比例,使和为1),其数学期望(这么算有可能有误,欢迎指出)为
E= (1+2+3+4+5+6+7)×0.4%+8×24.3%+9×32.4%+10×40.5%=9.02,意思是按照这个水位值,大概每9抽就能获得一个高级物品。
这个水位图上对应的概率,通常可能是由数值策划来操刀的,虽然其他数值不能精确确定,但只要声明了10次内必定出货,那么第十次的水位表一定是100%,99.99999%都不行,否则当某个玩家出现了抽10次结果一次都没出货的情况后,这就涉及到诚信危机了。

最多10次祈愿必定能通过保底获取4星或以上奖品,
通过保底获取4星概率为99.400%,获取 5星物品概率为0.600%

意味着每十连保底还是有可能获得5星的,但是概率只有0.6%,剩下的99.4%的概率都是4星物品。

2.1 10抽4星保底机制处理

由图中信息可知,4星和5星保底概率是增长,3星物品概率在保底机制下降低,因此判断保底的操作是在随机到3星区域的情况下进行操作的。方法是从1.1中随机到3星物品下再根据水位值进行再进行随机

一次随机到5701~100000时,机根据水位表进行二次随选择圈定保底概率,三次随机决定出4星还是5星,
四次随机决定具体的物品,当随机选中4星或者5星概率物品时,4星或5星的水位计数清零。

2.2 5星保底机制处理

由祈愿详情图的说明可知,5星的来源有三处,一是通过5星基础概率获得,二是通过2.1中10抽0.6%的概率获得,三是通过90抽计数获得。
同理,只要涉及保底,那么5星的90抽也会有水位表,此保底也是从3星区域操作。5星的水位表参考推测值如下:
90抽保底水位表

一次随机到5701~100000时,如2.1中的保底未被选中,按照90抽保底水位表进行第三次随机,
若抽出,则进行第四次随机选择5星角色还是武器,确定角色或者武器组后,第五次随机选择具体的角色和武器。

2.3 3星物品处理

这是最普遍的情况,随机到三星的武器,通常这部分是在处理四星和五星的产出后最后出现。

3 编写代码与实现

本次用Visual Studio 2019社区版,由于只是数据模拟,编写简单的控制台应用即可,语言C/C++,C#,Python等不限,这里选C++,如果是其他平台或者IDE,参考相应的编写控制台应用的教程即可。
考虑到读者各自的水平,有编程经验的或者老鸟直接看后面的代码即可,欢迎指正。

3.1 IDE简要引导

启动Visual Studio后,选择"Create a new project",创建一个新的工程。
创建新的工程
接下来语言选C++,平台选Windows,工程选Console,然后点Next输入工程名字即可,这张图是PS做的方便说明,正常情况三个选项只能出现一个,要依次选取,初学者悉知。
选择工程类型
如果没有模板甚至语言可选择,请参考其他关于如何安装Visual Studio组件的文章。
创建工程名字
创建空白工程
按照1~6的步骤添加文件,
添加工程文件
编写hello world测试代码并保存到工程目录,目录在第三张图location的位置,只改文件名,不要改扩展名,扩展名保持.cpp即可。
编写测试代码

在右侧工程栏的Source Files分组右键添加先前创建好的cpp文件
添加源文件到工程
完成后点击Local Windows Debugger看到hello world的控制台窗口则算成功,如报错请检查代码规范或者前面步骤是否出错。
启动调试

3.2 代码部分

完整代码如下,可直接复制粘贴运行

#include <iostream>
#include <iomanip> //计算有效数字引用库
#include <windows.h> //更改控制台字体颜色引用库
#include <random> //获取随机数库
//颜色代码,参考https://baike.baidu.com/item/SetConsoleTextAttribute/570121?fr=aladdin
constexpr auto FORE_GREEN = 0x0a;
constexpr auto FORE_YELLOW = 0x0e;
constexpr auto FORE_CYAN = 0x0b;
constexpr auto FORE_WHITE = 0x0f;
//更改控制台窗口字体颜色,随机数生成器函数声明
void fore_consolecolor(int wordcolor, const std::string putstr);
unsigned int luckynum_generator(int basenum);

int main()
{
	using namespace std;
	//参考1.1
    const int basenum = 100000, basenum_nd = 100;
    //按照角色和武器的星级进行分组,数据来源于常驻池说明
    const string weapon_3star[] = { "弹弓", "神射手之誓","鸦羽弓","翡玉法球","讨龙英杰谭","魔导绪论","黑缨枪",
                                    "以理服人","沐浴龙血的剑","铁影阔剑","飞天御剑","黎明神剑","冷刃" };
    
    const string char_4star[]   = { "辛焱", "砂糖", "迪奥娜", "重云", "诺艾尔", "班尼特", "菲谢尔", "凝光",
                                    "行秋", "北斗", "香菱", "安柏", "雷泽", "凯亚", "芭芭拉", "丽莎" }; 

    const string weapon_4star[] = { "弓藏", "祭礼弓", "绝弦", "西风猎弓", "昭心", "祭礼残章", "流浪乐章", "西风秘典", "西风长枪", 
                                    "匣里灭辰", "雨裁", "祭礼大剑", "钟剑", "西风大剑", "匣里龙吟", "祭礼剑", "笛剑", "西风剑" };

    const string char_5star[]   = { "刻晴" ,"莫娜" ,"七七" ,"迪卢克" ,"琴" };

    const string weapon_5star[] = { "阿莫斯之弓", "天空之翼", "四风原典", "天空之卷", "和璞鸢", 
                                    "天空之脊", "狼的末路", "天空之傲", "天空之刃", "风鹰剑" };
    //概率分隔数组,参考1.1
    const unsigned int lucky_range[3] = { 600,5700,100000 };
    //4星物品水位表,10抽保底机制,参考2.1
    const unsigned int wish_4star_poss[10] = { 1,  1,  1,  1,  1,  1,  1,  1,  35, 100 };
    //5星物品水位表,90抽保底机制,参考2.2
    const unsigned int wish_5star_poss[90] = { 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
                                               1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
                                               1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
                                               1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
                                               1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
                                               1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
                                               1,  1,  1,  1,  1,  2,  2,  2,  2,  55,
                                               60, 62, 64, 65, 70, 72, 73, 75, 80, 100 };

    //初始化随机数生成引擎
    srand(static_cast<unsigned int>(time(NULL)));
    static std::default_random_engine random_engine(static_cast<unsigned int>(time(NULL)));
    uint_fast32_t tmp = random_engine();

    //计算每个种类的物品数量和总数
    int weapon_3star_num = sizeof(weapon_3star) / sizeof(weapon_3star[0]);
    int char_4star_num = sizeof(char_4star) / sizeof(char_4star[0]);
    int weapon_4star_num = sizeof(weapon_4star) / sizeof(weapon_4star[0]);
    int char_5star_num = sizeof(char_5star) / sizeof(char_5star[0]);
    int weapon_5star_num = sizeof(weapon_5star) / sizeof(weapon_5star[0]);
    int poolsum = weapon_3star_num + char_4star_num + weapon_4star_num + char_5star_num + weapon_5star_num;
    //生成动态数组用于抽卡统计
    int* wishbox = new int[poolsum]();
	//输入字符变量,随机数存储数组,每个种类计数数组,抽卡数总计变量,循环计数变量
    char inputc = '0';
    unsigned int lucky_nums[8] = { 0 };
    int wish_category_count[5] = { 0 };
    int wish_4star_base = 0, wish_5star_base = 0;
    int wish_count_sum = 0;
    int ci = 0;
	//输入“1”(不带引号,后同)进行单抽,“2”进行十连抽,“n”(小写,后同)显示当前抽数,“s”显示详细统计信息,“c”退出抽卡
	//可连续输入(只要缓冲区够),比如“111”或“2222”按下enter键后可进行3次单抽或4次十连抽
    while(1)
    {
        std::cin >> inputc;
        if (inputc == 'c') {
            break;
        }

        switch (inputc)
        {
            case '1':
            {	//获得8组随机数并存储,用于后续分支判断
                lucky_nums[0] = luckynum_generator(basenum);
                lucky_nums[1] = luckynum_generator(basenum_nd);
                lucky_nums[2] = luckynum_generator(char_5star_num);
                lucky_nums[3] = luckynum_generator(weapon_5star_num);
                lucky_nums[4] = luckynum_generator(char_4star_num);
                lucky_nums[5] = luckynum_generator(weapon_4star_num);
                lucky_nums[6] = luckynum_generator(weapon_3star_num);
                lucky_nums[7] = luckynum_generator(basenum);

                //随机到0~599的6星物品区间执行分支,基础概率0.6%
                if (lucky_nums[0] < lucky_range[0]) {
                    wish_5star_base = 0;
                    //二次随机决定是角色还是武器,各占50%概率                  
                    if (lucky_nums[1] < basenum_nd / 2) {
                        //三次随机选定具体角色
                        //抽卡总计+1
                        wish_count_sum++;
                        //按顺序存储角色
                        wishbox[weapon_3star_num + char_4star_num + weapon_4star_num + lucky_nums[2]]++;
                        //标记控制台字体颜色,5星:金色,4星:青色,3星:绿色
                        fore_consolecolor(FORE_YELLOW, char_5star[lucky_nums[2]]);
                    }
                    else {
                        //抽卡计数+1,5星武器库存+1,逻辑和上面的分支类似
                        wish_count_sum++;
                        wishbox[weapon_3star_num + char_4star_num + weapon_4star_num + char_5star_num + lucky_nums[3]]++;
                        fore_consolecolor(FORE_YELLOW, weapon_5star[lucky_nums[3]]);
                    }
                    break;
                }
                //600~5699分支,获得四星物品,逻辑和上面类似
                else if (lucky_nums[0] < lucky_range[1]) {
                    wish_4star_base = 0;
                    //2nd random for 6star character or weapon each possibility is 50%
                    if (lucky_nums[1] < basenum_nd / 2) {
                        //3rd random for specific character
                        wish_count_sum++;
                        wishbox[weapon_3star_num + lucky_nums[4]]++;
                        fore_consolecolor(FORE_CYAN, char_4star[lucky_nums[4]]);
                    }
                    else {
                        wish_count_sum++;
                        wishbox[weapon_3star_num + char_4star_num + lucky_nums[5]]++;
                        fore_consolecolor(FORE_CYAN, weapon_4star[lucky_nums[5]]);
                    }
                    break;
                }
                // 5700~99999分支,主要获得三星物品
                else {
                    //10连抽保底处理,随着未抽中次数的增加,获得到物品的概率越来越高直到100%
                    if (lucky_nums[1] < wish_4star_poss[wish_4star_base] ) {
                        //抽中4星,概率99.400%
                        if (lucky_nums[7] > lucky_range[0]) {
                            wish_4star_base = 0;
                            wish_count_sum++;
                            //2nd random for 6star character or weapon each possibility is 50%
                            if (lucky_nums[1] < basenum_nd / 2) {
                                //3rd random for specific character
                                wishbox[weapon_3star_num + lucky_nums[4]]++;
                                fore_consolecolor(FORE_CYAN, char_4star[lucky_nums[4]]);
                            }
                            else {
                                wishbox[weapon_3star_num + char_4star_num + lucky_nums[5]]++;
                                fore_consolecolor(FORE_CYAN, weapon_4star[lucky_nums[5]]);
                            }
                            break;
                        }
                        //中5星,概率0.600%
                        else {
                            wish_5star_base = 0;
                            wish_count_sum++;
                            if (lucky_nums[1] < basenum_nd / 2) {
                                //3rd random for specific character
                                wishbox[weapon_3star_num + char_4star_num + weapon_4star_num + lucky_nums[2]]++;
                                fore_consolecolor(FORE_YELLOW, char_5star[lucky_nums[2]]);
                            }
                            else {
                                wishbox[weapon_3star_num + char_4star_num + weapon_4star_num + char_5star_num + lucky_nums[3]]++;
                                fore_consolecolor(FORE_YELLOW, weapon_5star[lucky_nums[3]]);
                            }
                            break;
                        }
                    }
                    //90抽保底中5星情况,代码逻辑和上方类似
                    if (lucky_nums[1] < wish_5star_poss[wish_5star_base]) {
                        wish_5star_base = 0;
                        wish_count_sum++;
                        if (lucky_nums[1] < basenum_nd / 2) {
                            //3rd random for specific character
                            wishbox[weapon_3star_num + char_4star_num + weapon_4star_num + lucky_nums[2]]++;
                            fore_consolecolor(FORE_YELLOW, char_5star[lucky_nums[2]]);
                        }
                        else {
                            wishbox[weapon_3star_num + char_4star_num + weapon_4star_num + char_5star_num + lucky_nums[3]]++;
                            fore_consolecolor(FORE_YELLOW, weapon_5star[lucky_nums[3]]);
                        }
                        break;
                    }
                    //获得三星物品,最常见的情况
                    wishbox[lucky_nums[6]]++;
                    wish_count_sum++;
                    fore_consolecolor(FORE_GREEN, weapon_3star[lucky_nums[6]]);
                    //抽中三星物品,10连抽保底和90抽保底+1
                    wish_5star_base++;
                    wish_4star_base++;
                    break;   
                }
                break;
            }
            case '2':
            {
                //十连抽和单抽代码基本一致,差异部分主要是加入循环和控制循环的语句
                for (ci = 0; ci < 10; ci++) {
                    lucky_nums[0] = luckynum_generator(basenum);
                    lucky_nums[1] = luckynum_generator(basenum_nd);
                    lucky_nums[2] = luckynum_generator(char_5star_num);
                    lucky_nums[3] = luckynum_generator(weapon_5star_num);
                    lucky_nums[4] = luckynum_generator(char_4star_num);
                    lucky_nums[5] = luckynum_generator(weapon_4star_num);
                    lucky_nums[6] = luckynum_generator(weapon_3star_num);
                    lucky_nums[7] = luckynum_generator(basenum);

                    //first random for wish
                    if (lucky_nums[0] < lucky_range[0]) {
                        wish_5star_base = 0;
                        wish_count_sum++;
                        //2nd random for character or weapon each possibility is 50%                    
                        if (lucky_nums[1] < basenum_nd / 2) {
                            //3rd random for specific character
                            //5星角色库存+1
                            wishbox[weapon_3star_num + char_4star_num + weapon_4star_num + lucky_nums[2]]++;
                            fore_consolecolor(FORE_YELLOW, char_5star[lucky_nums[2]]);
                        }
                        else {
                            //5星武器库存+1
                            wishbox[weapon_3star_num + char_4star_num + weapon_4star_num + char_5star_num + lucky_nums[3]]++;
                            fore_consolecolor(FORE_YELLOW, weapon_5star[lucky_nums[3]]);
                        }
                        continue;
                    }
                    else if (lucky_nums[0] < lucky_range[1]) {
                        wish_4star_base = 0;
                        wish_count_sum++;
                        //2nd random for 4star character or weapon each possibility is 50%
                        if (lucky_nums[1] < basenum_nd / 2) {
                            //3rd random for specific character
                            wishbox[weapon_3star_num + lucky_nums[4]]++;
                            fore_consolecolor(FORE_CYAN, char_4star[lucky_nums[4]]);
                        }
                        else {
                            wishbox[weapon_3star_num + char_4star_num + lucky_nums[5]]++;
                            fore_consolecolor(FORE_CYAN, weapon_4star[lucky_nums[5]]);
                        }
                        continue;
                    }
                    // 3star and floor possibility
                    else {
                        //10连抽保底情况
                        if (lucky_nums[1] < wish_4star_poss[wish_4star_base]) {
                            //中4星,概率99.400%
                            if (lucky_nums[7] > lucky_range[0]) {
                                wish_4star_base = 0;
                                wish_count_sum++;
                                //2nd random for 6star character or weapon each possibility is 50%
                                if (lucky_nums[1] < basenum_nd / 2) {
                                    //3rd random for specific character
                                    wishbox[weapon_3star_num + lucky_nums[4]]++;
                                    fore_consolecolor(FORE_CYAN, char_4star[lucky_nums[4]]);
                                }
                                else {
                                    wishbox[weapon_3star_num + char_4star_num + lucky_nums[5]]++;
                                    fore_consolecolor(FORE_CYAN, weapon_4star[lucky_nums[5]]);
                                }
                                continue;
                            }
                            //中5星,概率0.600%
                            else {
                                wish_5star_base = 0;
                                wish_count_sum++;
                                if (lucky_nums[1] < basenum_nd / 2) {
                                    //3rd random for specific character
                                    wishbox[weapon_3star_num + char_4star_num + weapon_4star_num + lucky_nums[2]]++;
                                    fore_consolecolor(FORE_YELLOW, char_5star[lucky_nums[2]]);
                                }
                                else {
                                    wishbox[weapon_3star_num + char_4star_num + weapon_4star_num + char_5star_num + lucky_nums[3]]++;
                                    fore_consolecolor(FORE_YELLOW, weapon_5star[lucky_nums[3]]);
                                }
                                continue;
                            }
                        }
                        //90抽保底中5星情况
                        if(lucky_nums[1] < wish_5star_poss[wish_5star_base]){
                            wish_5star_base = 0;
                            wish_count_sum++;
                            if (lucky_nums[1] < basenum_nd / 2) {
                                //3rd random for specific character
                                wishbox[weapon_3star_num + char_4star_num + weapon_4star_num + lucky_nums[2]]++;
                                fore_consolecolor(FORE_YELLOW, char_5star[lucky_nums[2]]);
                            }
                            else {
                                wishbox[weapon_3star_num + char_4star_num + weapon_4star_num + char_5star_num + lucky_nums[3]]++;
                                fore_consolecolor(FORE_YELLOW, weapon_5star[lucky_nums[3]]);
                            }
                            continue;
                        }
                         wishbox[lucky_nums[6]]++;
                         wish_count_sum++;
                         fore_consolecolor(FORE_GREEN, weapon_3star[lucky_nums[6]]);
                         wish_5star_base++;
                         wish_4star_base++;   
                    }
                }
                std::cout << endl;
                break;
            }
            case 'n':
            {
                //显示已抽卡总数
                std::cout << "祈愿数:";
                std::cout << wish_count_sum << endl;
                break;
            }
            case 's':
            {
                //分别显示已经抽中的物品及其数量,占比的统计信息
                wish_category_count[0] = 0;
                wish_category_count[1] = 0;
                wish_category_count[2] = 0;
                wish_category_count[3] = 0;
                wish_category_count[4] = 0;
                int counti = 0;
                for (counti = 0; counti < poolsum; counti++) {
                    if (wishbox[counti] > 0) {
                        if (counti < weapon_3star_num) {
                            std::cout << weapon_3star[counti] << ":" << wishbox[counti] << " ";
                            wish_category_count[0] += wishbox[counti];
                        }
                        else if (counti < (weapon_3star_num + char_4star_num)) {
                            std::cout << char_4star[counti - weapon_3star_num] << ":" << wishbox[counti] << " ";
                            wish_category_count[1] += wishbox[counti];
                        }
                        else if (counti < (weapon_3star_num + char_4star_num + weapon_4star_num)) {
                            std::cout << weapon_4star[counti - (weapon_3star_num + char_4star_num)] << ":" << wishbox[counti] << " ";
                            wish_category_count[2] += wishbox[counti];
                        }
                        else if (counti < (weapon_3star_num + char_4star_num + weapon_4star_num + char_5star_num)) {
                            std::cout << char_5star[counti - (weapon_3star_num + char_4star_num + weapon_4star_num)] << ":" << wishbox[counti] << " ";
                            wish_category_count[3] += wishbox[counti];
                        }
                        else {
                            std::cout << weapon_5star[counti - (weapon_3star_num + char_4star_num + weapon_4star_num + char_5star_num)] << ":" << wishbox[counti] << " ";
                            wish_category_count[4] += wishbox[counti];
                        }
                    }
                }
                counti = 0;
                std::cout << endl;
                std::cout << "祈愿数:";
                std::cout << wish_count_sum << endl;
                std::cout.setf(ios::fixed);
                std::cout << "3star_weapon: " << "(" << wish_category_count[0] << ") " << setprecision(2) << ((float)wish_category_count[0] / (float)wish_count_sum) * 100 << "%" << endl;
                std::cout << "4star_character: " << "(" << wish_category_count[1] << ") " << setprecision(2) << ((float)wish_category_count[1] / (float)wish_count_sum) * 100 << "%" << endl;
                std::cout << "4star_weapon: " << "(" << wish_category_count[2] << ") " << setprecision(2) << ((float)wish_category_count[2] / (float)wish_count_sum) * 100 << "%" << endl;
                std::cout << "5star_character: " << "(" << wish_category_count[3] << ") " << setprecision(2) << ((float)wish_category_count[3] / (float)wish_count_sum) * 100 << "%" << endl;
                std::cout << "5star_weapon: " << "(" << wish_category_count[4] << ") " << setprecision(2) << ((float)wish_category_count[4] / (float)wish_count_sum) * 100 << "%" << endl;
                break;
            }
            default:
                break;
        }
    }
	return 0;
}

//用wordcolor的颜色显示putstr字符串,颜色代码参考代码顶部的链接,显示完成后改为白字黑底。
void fore_consolecolor(int wordcolor, const std::string putstr)
{
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), wordcolor);
    std::cout << putstr << " ";
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FORE_WHITE);
}

//随机数生成函数,生成0~basenum-1范围内的随机数
unsigned int luckynum_generator(int basenum)
{
    int lucky_num = 0;
    srand(static_cast<unsigned int>(time(NULL)));
    static std::default_random_engine random_engine(static_cast<unsigned int>(time(NULL)));
    uint_fast32_t tmp = random_engine();
    tmp = random_engine();
    lucky_num = tmp % basenum;
    return lucky_num;
}


3.3 测试数据

测试一个数量数量相对较多的数据,如图所示:
数据测试
从统计数据中可见,3星物品85.36%,4星物品:13.07%,5星物品:1.58%,非常接近游戏运营方公布的概率,说明从数据上来说基本上还是符合概率要求。但是从理论计算上看,四星角色和武器,五星角色和武器数量应该大体相当的,但这个部分模拟的数据和说明有点出入,如有读者发现问题也欢迎指正。

3.4 需要改进和存在的问题

较多的if-else分支是写代码过程中困扰我的问题之一,这让代码的可读性变差,我试图减少一部分但是没有成功,在一个switch-case语句中塞一堆代码对结构的稳健性来说也并不是好事,如果在这种控制台环境下有更好的代码书写方案也欢迎各位指正。

此外这个代码与生产环境可能存在相当大的出入,甚至结构完全不一样都有可能。但可以推测游戏开发商能控制的因素更多,至于有没有诸如仓检之类的玄学,这个没有看过源码和玩家抽卡的大数据就真的不清楚了。

此外这个游戏除了常驻池还有UP池,其规则和常驻池有些差别,主要是提升了某些物品的概率,按照本文的代码去模拟UP池应该是问题不大的。

附图

常驻池说明原图

  • 13
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
【项目说明】 1.项目代码均经过功能验证ok,确保稳定可靠运行。欢迎下载食用体验! 2.主要针对各个计算机相关专业,包括计算机科学、信息安全、数据科学与大数据技术、人工智能、通信、物联网等领域的在校学生、专业教师、企业员工。 3.项目具有丰富的拓展空间,不仅可作为入门进阶,也可直接作为毕设、课程设计、大作业、初期项目立项演示等用途。 4.当然也鼓励大家基于此进行二次开发。在使用过程中,如有问题或建议,请及时沟通。 5.期待你能在项目中找到乐趣和灵感,也欢迎你的分享和反馈! 【资源介绍】 本Python库是用来模拟原神抽卡的,具体可以模拟角色活动祈愿、武器祈愿和常驻祈愿(暂不支持新手祈愿) # 安装方法 通过pip安装即可,复制下面的代码到命令行中即可 ```python pip install genshinwish ``` # `Wish()`类 用于设定卡初始状态并预备好抽卡。可以直接什么都不填,用`Wish()`来进行实例化,也可以自定义卡的信息和抽卡状态数据。 目前只能让一个对象进行实例化,在一个对象内不可以混合使用三种方法,因为水位是继承的。如果想在同意程序中抽别的子需要对另外一个对象实例化。后续的更新中可能会将这个问题修复。 (可选)输入参数如下: ## 卡信息 ### 限定角色祈愿 - `up_candidate`为限定角色祈愿中UP的五星角色,类型为`str`,默认值为`"纳西妲"` - `four_star_up`为限定角色祈愿中UP的四星角色,类型为长度为3的`list`,默认值为`["久岐忍", "多莉", "莱依拉"]` ### 限定武器祈愿 - `five_star_weapon_up`为限定武器祈愿中UP的五星武器,类型为长度为2的`list`,默认值为`["千夜浮梦", "圣显之钥"]` - `four_star_weapon_up`为限定武器祈愿中UP的四星武器星武器,类型为长度为5的`list`,默认值为`["绝弦", "祭礼残章", "匣里灭辰", "西风大剑", "西福斯的月光"]` ## 抽卡状态 ### 通用状态信息 - `draw_count`为抽卡水位统计,类型为`int`,默认值为`0`。 - `four_star_count`为四星物品水位统计,类型为`int`,默认值为`0`。 - `five_star_grt`为五星保底状态,类型为`bool`,默认值为`False`。当`five_star_grt=False`时,可能会歪,也可能不歪;当`five_star_grt=True`时,必定出本期UP五星物品。 - `four_star_grt`为四星保底状态,类型为`bool`,默认值为`False`。当`four_star_grt=False`时,可能会歪,也可能不歪;当`four_star_grt=True`时,必定出本期UP四星物品。 - `is_limited`判断是否为本期限定角色,类型为`bool`,默认值为`False`。 - `star`为物品星级,类型为范围在[3,5]的`int`,默认值为`3` - `is_character`判断上一抽结果是否为角色,类型为`bool`,默认值为`False` - `history`存储抽卡记录,类型为`list` ### 武器专用状态信息 - `chart_course`为定轨状态,类型应为`str`,默认值为`None`。 - `fate_points`为命定值,类型为范围在[0,2]的`int`,默认值为`0`. - `is_chart_course`最近一次出五星时,判断结果是否为定轨武器,类型为`bool`,默认值为`False`。 ## 使用示例 ```python from genshinwish import Wish wish = Wish(up_candidate="纳西妲", four_star_up=["久岐忍", "多莉", "莱依拉"]) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值