Python实现简单的《原神》抽卡系统模拟

用Python简单模拟《原神》抽卡系统[抽卡模拟器]

  • 简介
  • 代码思想
  • 保底机制
  • 概率
  • 概率公式
  • 代码构建
  • 导入软件包random和os
  • 初始化概率
  • 增加概率
  • 保底机制
  • 创建文件夹
  • 抽卡次数读取
  • 出金之后的判断
  • 10抽必出紫
  • 主体部分
  • 完整代码
  • 使用提醒
  • 记得在卡池放东西
  • UP角色
  • 五星常驻
  • 四星角色
  • 三星武器
  • 重要的事情重复一遍,别忘了往卡池放东西
  • 结束
  • 欢迎
    这是我第一次发布文章,就爱闲的没事整点活玩,写的不好还请见谅
    使用的语言是Python,因为实在是太方便了o(TヘTo)
    对了,要是懒得看代码思想直接跳到完整代码就彳亍

    简介

    想必大家都听说过原神吧,是米哈游开发的大世界探索游戏。大学一放假就太闲了,于是就用python写了个模拟原神抽卡的程序,其实星铁也适用这个机制
    大家可以用它来试试运气,我在测试的时候一次出了三金,两个纳西妲一个琴(炫耀)[为什么我游戏中就没这运气,天天大保底,气死了]
    好的,那么废话不多说,我们先说一下原理

    代码思想

    根据我从网上和官方给出的概率浏览获得的信息:

  • 保底机制

    180抽大保底,90抽小保底

  • 概率

    五星中奖概率为0.6%
    四星角色概率为2.55%
    其余的三星概率是96.85%
    大保底小报底各占50%
    五星概率会从第74抽开始逐渐提高6%

  • 概率公式

    概率 抽卡次数i
    0.006 (i<=73)
    0.006 + 0.06(i – 73) (74<=i<=89)
    1 (i=90)
  • 代码构建

    导入软件包random和os

    毕竟是抽卡,怎么能少了random
    然后这个os是新建文件夹用的
    用来保存你的抽卡记录,还有创建你的卡池

    import os
    import random
    

    初始化概率

    其实简单说说就是,先加入9685个蓝色,然后加入255个紫色,再加入6个金色,然后打乱

    # 初始化抽卡的概率
    def rate_initialization():
        rate_list.extend(['蓝' for temp in range(9685)])  # 蓝色概率是96.85%
        rate_list.extend(['紫' for temp in range(255)])  # 紫色概率是2.55%
        rate_list.extend(['金' for temp in range(60)])  # 金色概率是0.6%
        random.shuffle(rate_list)  # 打乱这个列表
    

    增加概率

    其实就是74抽之后,每次把60个蓝色去掉,然后随机插入60个金色
    啊,这个踹他的原因就是怕一开始初始化蓝色数量不够,其实没啥用,可以删掉

    # 74抽之后增加概率
    def rate_add():
        try:
            for _ in range(60):
                rate_list.remove('蓝')
                rate_list.insert(random.randint(0, len(rate_list) - 1), '金')
        except ValueError:
            print('程序异常,概率增加异常')
            exit()
    

    保底机制

    有点小长,说简单点其实就是检测是否有保底这个文本文档,如果有就读一下,没有就创建并写入false表示是小报底,true是大保底。如果是false就在up和常驻中随机抽取,抽到up还是false,抽到常驻变成true,就这么个原理

    # 大保底还是小保底
    def guarantees():
        try:
            with open('recording\\isGuarantees.txt', 'r', encoding='utf-8') as file:
                if file.read() == 'true':
                    certainly = True
                else:
                    certainly = False
        except BaseException:
            with open('recording\\isGuarantees.txt', 'w+', encoding='utf-8') as file:
                file.write('false')
            with open('recording\\isGuarantees.txt', 'r', encoding='utf-8') as file:
                if file.read() == 'true':
                    certainly = True
                else:
                    certainly = False
        if certainly:
            with open('recording\\isGuarantees.txt', 'w+', encoding='utf-8') as file:
                file.write('false')
            return True
        else:
            res = random.choice(['up', 'resident'])
            if res == 'up':
                with open('recording\\isGuarantees.txt', 'w+', encoding='utf-8') as file:
                    file.write('false')
                return True
            else:
                with open('recording\\isGuarantees.txt', 'w+', encoding='utf-8') as file:
                    file.write('true')
                return False
    

    创建文件夹

    其实注释都说了,不存在就新建一个,存在就拉倒

    # 创建一个文件夹在同一个目录下
    def mkdir(path):
        folder = os.path.exists(path)
        if not folder:  # 判断文件夹是否存在
            os.makedirs(path)  # 不存在就新建一个
    

    抽卡次数读取

    这个其实和上面的保底一样的,找不到文件就新建一个,然后初始化为0

    # 抽卡次数读取
    def read_times():
        try:
            with open('recording\\times.txt', 'r', encoding='utf-8') as file:
                number = int(file.read())
                return number
        except BaseException:
            with open('recording\\times.txt', 'w+', encoding='utf-8') as file:
                file.write('0')
            return 0
    

    出金之后的判断

    这就是为什么上面的保底返回的是True和False,出了就append一个up角色,歪了就append一个常驻的角色上去

    # 出金了
    def gold():
        rate_initialization()
        record_times(0)
        if guarantees():
            res_list.append(up)
            return '出货了!!!!!'
        else:
            res_list.append(random.choice(fiveStar))
            return '哇!金色传。。。歪了。。。'
    

    10抽必出紫

    第十抽必是紫色,如果不满10抽出了紫色,那么记录则会清零,这是记录和读取的函数

    # 记录紫色保底,10抽必出紫色
    def record_rare(number):
        with open('recording\\rare.txt', 'w+', encoding='utf-8') as file:
            file.write(str(number))
    
    # 读取紫色保底
    def read_rare():
        try:
            with open('recording\\rare.txt', 'r', encoding='utf-8') as file:
                return int(file.read())
        except BaseException:
            with open('recording\\rare.txt', 'w+', encoding='utf-8') as file:
                file.write('0')
                return 0
    

    主体部分

    其实就是把刚刚的方法或者叫函数也行,统合到了一起初始化卡池,读取,打乱,因为每次抽卡都会有一个动画告诉你是蓝天白云还是出货了,还是只有紫色,所以加了一个描述的打印输出。然后每次出金色都会重置概率,重新初始化,其余的就是照着我写的代码思想写的,其实也不是很难

    mkdir('卡池')
    mkdir('recording')
    while True:
        try:
            with open('卡池\\up.txt', 'r', encoding='utf-8') as tempFile:
                up = tempFile.read()
            with open('卡池\\fiveStar.txt', 'r', encoding='utf-8') as tempFile:
                fiveStar = tempFile.read().split(sep=' ')
            with open('卡池\\fourStar.txt', 'r', encoding='utf-8') as tempFile:
                fourStar = tempFile.read().split(sep=' ')
            with open('卡池\\threeStar.txt', 'r', encoding='utf-8') as tempFile:
                threeStar = tempFile.read().split(sep=' ')
            break
        except BaseException:
            print('你好,欢迎使用本模拟器,我在上面帮你创建了几文件夹,在里面填入卡池的东西就好了,用空格隔开')
            with open('卡池\\up.txt', 'w+', encoding='utf-8'):
                pass
            with open('卡池\\fiveStar.txt', 'w+', encoding='utf-8'):
                pass
            with open('卡池\\fourStar.txt', 'w+', encoding='utf-8'):
                pass
            with open('卡池\\threeStar.txt', 'w+', encoding='utf-8'):
                pass
            input('填好了就回个车')
    rate_list = list()
    rate_initialization()
    while True:
        try:
            wish = int(input('1、单抽 2、十连抽 3、退出\n请输入:'))
        except ValueError:
            print('你这输入的啥玩意')
            continue
        if wish == 1:
            count = 1
        elif wish == 2:
            count = 10
        elif wish == 3:
            break
        else:
            print('奇奇怪怪的数字')
            continue
        res_list = []
        result_report = '蓝天白云'
        temp_list = [random.choice(rate_list) for _ in range(count)]
        flag = False
        for character_rank in temp_list:
            if 73 <= read_times() <= 88:
                rate_add()
            elif read_times() >= 89:
                result_report = gold()
                continue
            record_times(read_times() + 1)
            if character_rank == '蓝':
                record_rare(read_rare() + 1)
                if read_rare() >= 10:
                    if not flag:
                        result_report = '出了个紫色'
                    record_rare(0)
                    res_list.append(random.choice(fourStar))
                    continue
                res_list.append(random.choice(threeStar))
            elif character_rank == '紫':
                if not flag:
                    result_report = '出了个紫色'
                record_rare(0)
                res_list.append(random.choice(fourStar))
            elif character_rank == '金':
                flag = True
                result_report = gold()
        print(result_report)
        print(' '.join(res_list))
        # recode_gacha()
        print('==================================================')
    

    接下来是完整代码

    完整代码

    """
    要求:180抽大保底,90抽小保底
    10抽必出4星
    90抽必出5星  抽到的时候up和常驻各占50%
    P = {
    0.006                       i<=73
    0.006 + 0.06(i - 73)        74<=i<=89
    1                           i=90
    }
    五星中奖概率为0.6%
    四星角色概率为2.55%
    其余的三星概率是96.85%
    大保底小报底各占50%
    """
    import os
    import random
    
    
    # 初始化抽卡的概率
    def rate_initialization():
        rate_list.extend(['蓝' for temp in range(9685)])
        rate_list.extend(['紫' for temp in range(255)])
        rate_list.extend(['蓝' for temp in range(60)])
        random.shuffle(rate_list)
    
    
    # 74抽之后增加概率
    def rate_add():
        try:
            for _ in range(60):
                rate_list.remove('蓝')
                rate_list.insert(random.randint(0, len(rate_list) - 1), '金')
        except ValueError:
            print('程序异常,概率增加异常')
            exit()
    
    
    # 大保底还是小保底
    def guarantees():
        try:
            with open('recording\\isGuarantees.txt', 'r', encoding='utf-8') as file:
                if file.read() == 'true':
                    certainly = True
                else:
                    certainly = False
        except BaseException:
            with open('recording\\isGuarantees.txt', 'w+', encoding='utf-8') as file:
                file.write('false')
            with open('recording\\isGuarantees.txt', 'r', encoding='utf-8') as file:
                if file.read() == 'true':
                    certainly = True
                else:
                    certainly = False
        if certainly:
            with open('recording\\isGuarantees.txt', 'w+', encoding='utf-8') as file:
                file.write('false')
            return True
        else:
            res = random.choice(['up', 'resident'])
            if res == 'up':
                with open('recording\\isGuarantees.txt', 'w+', encoding='utf-8') as file:
                    file.write('false')
                return True
            else:
                with open('recording\\isGuarantees.txt', 'w+', encoding='utf-8') as file:
                    file.write('true')
                return False
    
    
    # 创建一个文件夹在同一个目录下
    def mkdir(path):
        folder = os.path.exists(path)
        if not folder:  # 判断文件夹是否存在
            os.makedirs(path)  # 不存在就新建一个
    
    
    # 抽卡次数记录
    def record_times(number):
        with open('recording\\times.txt', 'w+', encoding='utf-8') as file:
            file.write(str(number))
    
    
    # 抽卡次数读取
    def read_times():
        try:
            with open('recording\\times.txt', 'r', encoding='utf-8') as file:
                number = int(file.read())
                return number
        except BaseException:
            with open('recording\\times.txt', 'w+', encoding='utf-8') as file:
                file.write('0')
            return 0
    
    
    # 出金了
    def gold():
        rate_initialization()
        record_times(0)
        if guarantees():
            res_list.append(up)
            return '出货了!!!!!'
        else:
            res_list.append(random.choice(fiveStar))
            return '哇!金色传。。。歪了。。。'
    
    
    # 记录紫色保底,10抽必出紫色
    def record_rare(number):
        with open('recording\\rare.txt', 'w+', encoding='utf-8') as file:
            file.write(str(number))
    
    
    # 读取紫色保底
    def read_rare():
        try:
            with open('recording\\rare.txt', 'r', encoding='utf-8') as file:
                return int(file.read())
        except BaseException:
            with open('recording\\rare.txt', 'w+', encoding='utf-8') as file:
                file.write('0')
                return 0
    
    
    # 写入抽卡记录
    def recode_gacha():
        with open('抽卡记录.txt', 'r', encoding='utf-8') as file:
            record_list = file.read()
            if len(record_list) >= 300:
                with open('抽卡记录.txt', 'a+', encoding='utf-8') as writeFile:
                    pass
                file.write(' '.join(res_list))
            else:
                with open('抽卡记录.txt', 'a+', encoding='utf-8') as writeFile:
                    pass
    
    
    mkdir('卡池')
    mkdir('recording')
    while True:
        try:
            with open('卡池\\up.txt', 'r', encoding='utf-8') as tempFile:
                up = tempFile.read()
            with open('卡池\\fiveStar.txt', 'r', encoding='utf-8') as tempFile:
                fiveStar = tempFile.read().split(sep=' ')
            with open('卡池\\fourStar.txt', 'r', encoding='utf-8') as tempFile:
                fourStar = tempFile.read().split(sep=' ')
            with open('卡池\\threeStar.txt', 'r', encoding='utf-8') as tempFile:
                threeStar = tempFile.read().split(sep=' ')
            break
        except BaseException:
            print('你好,欢迎使用本模拟器,我在上面帮你创建了几文件夹,在里面填入卡池的东西就好了,用空格隔开')
            with open('卡池\\up.txt', 'w+', encoding='utf-8'):
                pass
            with open('卡池\\fiveStar.txt', 'w+', encoding='utf-8'):
                pass
            with open('卡池\\fourStar.txt', 'w+', encoding='utf-8'):
                pass
            with open('卡池\\threeStar.txt', 'w+', encoding='utf-8'):
                pass
            input('填好了就回个车')
    rate_list = list()
    rate_initialization()
    while True:
        try:
            wish = int(input('1、单抽 2、十连抽 3、退出\n请输入:'))
        except ValueError:
            print('你这输入的啥玩意')
            continue
        if wish == 1:
            count = 1
        elif wish == 2:
            count = 10
        elif wish == 3:
            break
        else:
            print('奇奇怪怪的数字')
            continue
        res_list = []
        result_report = '蓝天白云'
        temp_list = [random.choice(rate_list) for _ in range(count)]
        flag = False
        for character_rank in temp_list:
            if 73 <= read_times() <= 88:
                rate_add()
            elif read_times() >= 89:
                result_report = gold()
                continue
            record_times(read_times() + 1)
            if character_rank == '蓝':
                record_rare(read_rare() + 1)
                if read_rare() >= 10:
                    if not flag:
                        result_report = '出了个紫色'
                    record_rare(0)
                    res_list.append(random.choice(fourStar))
                    continue
                res_list.append(random.choice(threeStar))
            elif character_rank == '紫':
                if not flag:
                    result_report = '出了个紫色'
                record_rare(0)
                res_list.append(random.choice(fourStar))
            elif character_rank == '金':
                flag = True
                result_report = gold()
        print(result_report)
        print(' '.join(res_list))
        # recode_gacha()
        print('==================================================')
    

    使用提醒

    记得在卡池放东西

    记得要在卡池里放东西,因为这个为了灵活控制卡池,比如新增什么常驻,四星角色,或者三星武器什么的,用的读取文本文档的方式来进行卡池数据的储存的,虽然数据库也可以,但是多少有点大材小用了。
    我这里给出一些我写好的用例吧,记得角色和角色,或者是武器和武器之间要用空格隔开,因为我这个是split(sep=’ ')劈分的是空格。我这里写了部分4星和目前5星常驻的角色,三星实在太多了,写不动了,这里我放出来

    UP角色

    up.txt

    就写一个限定角色就行,我写的纳西妲,因为我最喜欢纳西妲了

    五星常驻

    fiveStar.txt

    刻晴 莫娜 七七 迪卢克 琴 迪希雅 提纳里

    四星角色

    fourStar.txt

    安柏 丽莎 凯亚 芭芭拉 雷泽 菲谢尔 班尼特 诺艾尔 菲谢尔 砂糖 迪奥娜 北斗 凝光 香菱 行秋 重云 辛焱 绮罗罗

    三星武器

    threeStar.txt

    这个我没写,我就写了个蓝色,有兴趣的可以自己写一下,反正也是狗粮,我就不写了

    重要的事情重复一遍,别忘了往卡池放东西

    结束

    那么就到这里吧,感谢能读到这,我是喜欢整活的小狐,每天整点活玩就是我的乐趣。想想下次能玩点什么新花样,如果觉得有意思的话,还请点一个小小的赞。目前在忙项目,只能实现简单的逻辑,交互什么的下次一定。有时间再写到Django里。

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python实现简单的《原神》抽卡系统模拟

    发表评论