前言
最近迷上了《原神》这款游戏,其中的抽卡系统也是很让人上瘾,尤其是1.3版本更新中魈的up池的开启,不知不觉氪金数额已近千元。看着瘪瘪的腰包,我想:为什么不自己写一个抽卡系统,爽个够?
说干就干
基本思路
原神的抽卡系统可以建立在单抽的基础上,主要有单抽和十连这两种选项。抛开其概率的设定不说,卡池分别包含五星角色(因为是模拟的魈up池所以没有五星武器)、四星角色、四星武器和三星武器。五星和四星又分别有保底政策。在抽卡函数之外,还需要一定的交互界面,比如查询、充值等选项。
大致思路如上,以下为具体做法
抽卡基本函数
先来个这个:
import random
抽卡概率设定
此处我使用的是random函数,由于也不是很懂设置概率的操作,直接就用生成随机数,再判断随机数的区间,只要把区间范围圈定,可以简单地设置抽卡的概率。代码如下:
def single():
"""不保底时的抽奖"""
i = random.randint(1, 10001)#生成10000个整数
if i in range(1, 61):#五星中奖概率为0.6%
a = random.randint(0, 5)
star = st5[a]
stat.num_5 = 0
elif i in range(61, 316):#四星角色概率为2.55%
cha = random.randint(0, len(cha_4)-1)
star = cha_4[cha]
stat.num_4 = 0
elif i in range(316, 571):#四星武器概率为2.55%
wea = random.randint(0, len(weapon_4)-1)
star = weapon_4[wea]
stat.num_4 = 0
elif i in range(571, 10001):#其余为三星
star = '三星'
else:
#不知道为什么,实际操作中总是会生成写奇奇怪怪的
#东西,为了不影响原函数,这里else直接忽视
return None
if star == up:
stat.num_5 = 0
stat.up_num = 0
add(star)#这个函数会在后面解释
卡池
为了不影响阅读,还是把卡池内容贴上吧
"""卡池内容(未设置四星up角色)"""
up = '魈'
st5 = [up, up, up, up, up, '刻晴', '莫娜', '七七', '迪卢克', '琴']
cha_4 = ['安柏', '丽莎', '凯亚', '芭芭拉', '雷泽', '菲谢尔', '班尼特', '诺艾尔', '菲谢尔', '砂糖',
'迪奥娜', '北斗', '凝光', '香菱', '行秋', '重云', '辛焱']
weapon_4 = ['弓藏', '祭礼弓', '绝弦', '西风猎弓', '昭心', '祭礼残章', '流浪乐章', '西风秘典', '西风长枪',
'雨裁', '匣里灭辰', '祭礼大剑', '钟剑', '西风大剑', '匣里龙吟', '祭礼剑', '笛剑', '西风剑', '岩盔丘丘王']
st4 = weapon_4 + cha_4
get = []#这是每次抽奖后存储抽出内容的列表
have = []#这是存储总抽出内容的列表
保底策略
写程序的时候,这个是让我比较头疼的地方。一开始我想用简单的if-else,未果后尝试while,最后才想起来正解:引入跟踪游戏数据的类
class Stats:
"""跟踪游戏统计信息"""
def __init__(self):
self.total = 0#记录总抽卡次数(似乎没用到)
self.up_num = 0#记录up保底次数(180发保底)
self.num_4 = 0#记录四星保底次数(10发保底)
self.num_5 = 0#记录五星保底次数(90发保底)
self.stone = 0#这个用于充值系统,记录原石数
本来需要考虑到“抽到五星后,下一个五星必为up角色这一政策,但是嗯…我的方法的执行效果似乎是一样的
利用这个统计信息,每抽一次卡,如果没有出现期望的物品,对应数据就会+1,从而累积起来,到达保底数时,触发保底政策。
保底函数如下
def check_up():
"""检查保底"""
if stat.up_num < 179:#检查up角色保底
if stat.num_5 < 89:#检查五星保底
if stat.num_4 < 9:#检查四星保底
single()#如果没到保底,就正常抽卡
else:
#如果到保底了,就直接送出期望物品
o_4 = random.randint(0, len(st4) - 1)
star = st4[o_4]
add(star)
stat.num_4 = 0
else:#同理,不赘述了
o_5 = random.randint(0, len(st5) - 1)
star = st5[o_5]
add(star)
stat.num_5 = 0
else:
star = up
add(star)
stat.up_num = 0
但还是有一点小小的问题:假如,这一抽既是五星保底的第九十发,也是四星保底的第十发,此时到底该出五星还是四星。不是很清楚米哈游如何解决这个问题,抽奖文案中也没有提及。我就偷个懒不考虑了,直接设置优先级:up>五星>四星,嘿嘿
另外,关于对运行数据的累计,那个函数会在下一节提到。也不难想不是
抽卡结束做什么
也就是上面提到的function:add()
这个函数会在每次抽卡后执行,不管是触发保底还是正常抽卡,主要做记录结果的工作
代码如下:
def add(star):
"""每次抽卡完毕的常规操作"""
record(star)#记录保底数据
get.append(star)#将抽到的物品加入单次显示
have.append(star)#将抽到的内容加入背包
stat.total += 1#抽奖次数记录+1(真的没用到)
record()函数负责记录保底数据,代码如下:
def record(star):
"""记录数据变化"""
if star != '魈':#抽不到就加一
stat.up_num += 1
if star not in st4:
stat.num_4 += 1
if star not in st5:
stat.num_5 += 1
统计背包
抽完卡后,背包have列表还是比较凌乱的,我对其借用了个统计,制成字典以更条理地显示所获物品
def remember():
"""统计抽卡内容"""
value_cnt = {}#将中奖添加到列表里
for h in have:
value_cnt[h] = value_cnt.get(h, 0) + 1
print(value_cnt)
抽奖操作
这里分为单抽和十连,由于每次抽奖都需要在get列表中显示抽奖结果,两种函数均需在调用时清空get[]
单抽函数代码如下:
def extract():
"""单抽"""
if stat.stone >= 160:#这里添加了个判断原石
del get[:]
check_up()
stat.stone -= 160
print(get)
else:#充值系统我放在交互程序的文件里了
print('您的原石不足,请充值!')
十连函数如下:
def ten():
"""十连函数"""
if stat.stone >= 1600:
del get[:]
for num in range(0, 10):#操作十次
check_up()
stat.stone -= 1600
print(get)
else:
print('您的原石不足,请充值!')
至此,抽卡系统已制作完成,下面是交互系统的制作
交互系统
这一部分比较简单,就是各种逻辑判断,运行时也只是在python终端里通过用户输入来实现,相对而言较为简陋。
需要引入的库:
import main#也就是上面那个抽奖系统
from time import sleep
首先是开始运行的显示
print('正在加载配置文件...')
sleep(1)#嘿嘿,加点儿正式感
print('欢迎使用《原神》模拟抽卡系统,随时输入q以退出')
while True:
print('请输入对应字母以进入相应功能:\n[A]开始祈愿\t[B]祈愿记录\t[C]充值\t[q]退出')
msg = input('')
开始祈愿
话不多说,上代码
if msg.title() == 'A':
yi = input('请选择:\n[A]祈愿1次\t[B]祈愿10次\n')
if yi.title() == 'A':
sleep(1)#sleep,营造氛围嘛
main.extract()
sleep(0.5)
continue
elif yi.title() == 'B':
sleep(1)
main.ten()
sleep(0.5)
continue
elif yi.title() == 'q':
break
else:
print('请输入正确的选项!')
sleep(1)
continue
祈愿记录
if msg.title() == 'B':
num = len(main.have)
print('您已进行' + str(num) + '次祈愿')
print('其中有:')
main.remember()#显示背包的统计
sleep(1.5)
continue
充值系统
用了冗长的判断,好丑
if msg.title() == 'C':
print('您当前原石余额为:' + str(main.stat.stone))
chose = input('请选择充值金额:\n[A]6元(加赠60原石)\t[B]30元(加赠300原石)\t[C]98元(加赠980原石)'
'\n[D]198元(加赠1980原石)\t[E]328元(加赠3280原石)\t[F]648元(加赠6480原石)\n[G]返回\n')
if chose.title() == 'A':
main.stat.stone += 120
elif chose.title() == 'B':
main.stat.stone += 600
elif chose.title() == 'C':
main.stat.stone += 1960
elif chose.title() == 'D':
main.stat.stone += 3960
elif chose.title() == 'E':
main.stat.stone += 6480
elif chose.title() == 'F':
main.stat.stone += 12960
elif chose.title() == 'G':
continue
elif chose == 'q':
break
else:
print('请输入正确的选项!')
continue
print('充值成功!当前余额为:' + str(main.stat.stone))
sleep(1.5)
continue
退出
#while...
if msg == 'q':
break
print('感谢您使用模拟抽卡系统,祝您游戏愉快!')
sleep(1.5)
结语
这个抽卡系统还不是很完善,交互界面也比较丑陋,只能说是做了最底层的逻辑。这也是我在学了一个月python后第一次独立的项目实训,确实从中感到了编程的乐趣。
如果有什么对代码有补充的地方,欢迎在评论区交流。喜欢的话,也请点个小小的赞
此项目已上传GitHub,地址:https://github.com/juer-joker/Genshin