利用Python写一个抽奖程序,解密游戏内抽奖的秘密

前言

本文的文字及图片来源于网络,仅供学习、交流使用,不具备任何商业用途,版权归原做者全部,若有问题请及时联系咱们以做处理。mysql

做者: 极客挖掘机sql

PS:若有须要Python学习资料的小伙伴能够加点击下方连接自行获取数据库

http://note.youdao.com/noteshare?id=3054cce4add8a909e784ad934f956cef缓存

分析需求

咱们先整理下思路,目标是什么? 目标是要写一个抽奖程序,那么抽奖程序的核心是什么? 固然是如何判断一我的中奖了。那么如何判断一我的中奖呢? 是否是能够经过随机函数来操做呢?网络

中奖方法

一步一步来,咱们先经过随机函数来判断是否中奖。代码是否是能够先写成下面这样:并发

1 import random 2 3 # 判断中奖函数
4 def lottery(): 5     flag = random.randint(0, 9) 6     if flag < 2: 7         return True 8     else: 9         return False

首先,咱们获取 0 ~ 9 之间的随机正整数(这里不讨论 random 是否是真随机,从狭义上来说咱们能够认为它是随机的),若是中奖率为 20% 的话,咱们能够认为小于 2 的数字为中奖,其他的为没有中奖。而后中奖后返回 True ,没有中奖返回 False 。dom

咱们加一个入口测试函数,测试一下上面的代码是否能正常运行,而且中奖率是否能维持在大约 20 % 左右。函数

 1 if __name__ == '__main__':  2     # 中奖次数
 3     a = 0  4     # 没有中奖次数
 5     b = 0  6     for i in range(1000000) :  7         if (lottery()):  8             a += 1
 9         else: 10             b += 1
11 12     print('共计中奖:', a, ',未中奖:', b)

执行结果:学习

共计中奖: 200145 ,未中奖: 799855

上面的测试总共循环了 1 百万次,大约执行须要 2 ~ 3 秒左右,速度仍是蛮快的。能够看到,中奖结果确实接近 20% 左右。测试

动态中奖率

难道到这里就结束了么?固然不可能,这里只是刚刚开了个头。

若是这时老板说,你这个几率不能调整啊,须要让中奖率能够动态调整的,活动刚开始的时候中奖率要高,随着时间的推移,中奖率要降下来。

这时候咋整,傻眼了吧。

既然中奖率要可调整,那么咱们中奖率就不能定死在程序中了,这个中奖率须要有一个地方去作存储,在每次作随机的时候将这个中奖率取出来。

简单易行的方法就是将这个中奖率放在数据库中或者缓存服务中,这个根据实际业务场景来定。通常是根据预估访问压力的大小来进行技术选型,若是压力不是特别大,那么放在数据库中也是能够的,若是并发会比较高的话,建议仍是放在缓存中。

咱们来写一个从数据库获取中奖几率的方法(为了展现直观,小编这里直接使用 Mysql 数据库用做数据存储),先看下数据库的数据:

在这里插入图片描述

很简单的设计了一张表,里面有意义的字段有两个,一个用做中奖率的分子部分,一个用做中奖率的分母部分。分母部分最好要设置成 100 、 1000 、 10000 这种,这样计算中奖率会比较好计算。

 1 def get_lottery_rate():  2     conn = pymysql.connect(host='localhost', user='root', password='password', database='test', charset='utf8mb4')  3     try:  4         sql = 'SELECT fenzi, fenmu FROM rate'
 5         cursor = conn.cursor()  6  cursor.execute(sql)  7         result = cursor.fetchone()  8         return result  9     except Exception as ex: 10         print(ex) 11     finally: 12         conn.close()

运行这个方法测试结果以下:

(10, 100)

能够看到,咱们得到了一个元组,里面的内容就是咱们从数据库取出来的分子和分母。

咱们将前面的抽奖的那个方法改一下,改为从数据库获取中奖比例。修改后的代码以下:

1 def lottery(): 2     rate = get_lottery_rate() 3     flag = random.randint(1, rate[1]) 4     if flag < rate[0]: 5         return True 6     else: 7         return False

仍是运行上面的测试方法,这里要注意下,由于咱们如今是从数据库获取数据,每次方法执行都要加上数据库连接的创建与销毁,建议将循环次数修改成 1000 之内,否则执行的时间就有点太长了。

小编这里将循环次数修改成 1000 次后,执行结果以下:

共计中奖: 92 ,未中奖: 908

那么到这里,咱们就能够经过修改数据库中数据实时的操做中奖率了。固然上面的慢的问题咱们可使用数据库链接池等技术进行优化。

增长奖项

那么是否就结束了呢?no no no,咱们接着加需求。

如今,咱们只能知道每次到底中不中奖,只有一个奖项,可是如今想变成 3 个奖项,如:一等奖、二等奖、三等奖那该怎么办?

这个对以前的抽奖方法改动就有点大了,首先咱们先在数据库增长出来另外两个奖项的配置:

在这里插入图片描述

配置这里三个奖项的分母最好保持一致,不然后续计算会徒增复杂度。

修改咱们获取配置的那个方法:

 1 def get_lottery_rate():  2     conn = pymysql.connect(host='localhost', port = 3306, user='root', password='password', database='test', charset='utf8mb4')  3     try:  4         sql = 'SELECT * FROM rate order by id asc '
 5         cursor = conn.cursor()  6  cursor.execute(sql)  7         result = cursor.fetchall()  8         return result  9     except Exception as ex: 10         print(ex) 11     finally: 12         conn.close()

测试调用后结果以下:

((1, 10, 100), (2, 5, 100), (3, 1, 100))

先在咱们要作的是要将这个配置融入进咱们以前的中奖的那个方法中,很少说,直接上代码:

 1 # 判断中奖函数
 2 def lottery():  3     config = get_lottery_rate()  4     flag = random.randint(1, config[0][2])  5     if flag <= config[0][1]:  6         return 1
 7     elif flag > config[0][1] and flag <= (config[1][1] + config[0][1]):  8         return 2
 9     elif flag > (config[1][1] + config[0][1]) and flag <= (config[2][1] + config[1][1]): 10         return 3
11     else: 12         return 0

接着修改咱们的作测试的代码:

 1 def main():  2     # 一等奖中奖次数
 3     a = 0  4     # 二等奖中奖次数
 5     b = 0  6     # 三等奖中奖次数
 7     c = 0  8     # 未中奖次数
 9     d = 0 10     # 循环次数
11     e = 0 12     for i in range(1000): 13         e += 1
14         print('当前循环次数:', e) 15         result = lottery() 16         print('当前中奖结果:', result) 17         if (result == 1): 18             a += 1
19         elif (result == 2): 20             b += 1
21         elif (result == 3): 22             c += 1
23         else: 24             d += 1
25 
26     print('一等奖中奖:', a, ',二等奖中奖次数:', b, ',三等奖中奖次数:', c, ',未中奖次数:', d)

调用咱们的测试方法:

if __name__ == '__main__': main()

小编这里的运行结果以下:

在这里插入图片描述

 

增长会员判断

到这里咱们还没完,还能加需求,如今网站大多数都是会员制的,好比白银会员,黄金会员,钻石会员,若是不一样的会员等级须要有不一样的中奖率,这个是很正常的一件事儿,小编如今还清晰的记得当年某家大型互联网公司代码中的注释 “穷逼 VIP(活动送的那种)” 。

咱们假设钻石会员的中奖率为总体中奖率的 100% ,黄金会员的中奖率为总体中奖率的 50% ,白银会员的中奖率为总体中奖率的 20% 。

最简单的实现方式是直接在最外层套一层会员中奖率的判断,不知道各位同窗怎么想。

小编这里给出本身的解决方案:

# 判断会员等级中奖率过滤
# 会员等级 1.白银会员 2.黄金会员 3. 钻石会员
def vip_lottery(level):
   rate = random.randint(1, 10)
   # 若是是钻石会员,直接进入抽奖函数
   if level == 3:
       return lottery()
   # 若是是黄金会员, 50% 几率进入抽奖函数
   elif level == 2:
       if rate <= 5:
           return lottery()
       else:
           return 0
   # 若是是白银会员, 20% 几率进入抽奖函数
   elif level == 1:
       if rate <= 2:
           return lottery()
       else:
           return 0
   # 若是是其余,直接返回未中奖
   else:
       return 0

咱们新增一个测试增长会员过滤的测试方法:

# 会员制中奖测试方法
def test_vip():
   print('请输入您当前的会员等级:1.白银会员 2.黄金会员 3. 钻石会员')
   level = input()
   result = vip_lottery(int(level))
   if (result == 1):
       print('恭喜您中了一等奖')
   elif (result == 2):
       print('恭喜您中了二等奖')
   elif (result == 3):
       print('恭喜您中了三等奖')
   else:
       print('未中奖,谢谢惠顾')

在咱们的入口函数中调用这个方法:

if __name__ == '__main__':
   test_vip()

最终测试结果以下: 在这里插入图片描述 小编的人品还能够嘛,直接就能中三等奖。

 1 import random  2 import pymysql  3  4 # 获取中奖配置
 5 def get_lottery_rate():  6     conn = pymysql.connect(host='114.67.111.196', port = 3306, user='root', password='wsy@123456', database='test', charset='utf8mb4')  7     try:  8         sql = 'SELECT * FROM rate order by id asc '
 9         cursor = conn.cursor() 10  cursor.execute(sql) 11         result = cursor.fetchall() 12         return result 13     except Exception as ex: 14         print(ex) 15     finally: 16  conn.close() 17 18 # 判断中奖函数
19 def lottery(): 20     config = get_lottery_rate() 21     flag = random.randint(1, config[0][2]) 22     if flag <= config[0][1]: 23         return 1
24     elif flag > config[0][1] and flag <= (config[1][1] + config[0][1]): 25         return 2
26     elif flag > (config[1][1] + config[0][1]) and flag <= (config[2][1] + config[1][1]): 27         return 3
28     else: 29         return 0 30 31 # 判断会员等级中奖率过滤
32 # 会员等级 1.白银会员 2.黄金会员 3. 钻石会员
33 def vip_lottery(level): 34     rate = random.randint(1, 10) 35     # 若是是钻石会员,直接进入抽奖函数
36     if level == 3: 37         return lottery() 38     # 若是是黄金会员, 50% 几率进入抽奖函数
39     elif level == 2: 40         if rate <= 5: 41             return lottery() 42         else: 43             return 0 44     # 若是是白银会员, 20% 几率进入抽奖函数
45     elif level == 1: 46         if rate <= 2: 47             return lottery() 48         else: 49             return 0 50     # 若是是其余,直接返回未中奖
51     else: 52         return 0 53 54 # 批量测试方法
55 def test(): 56     # 一等奖中奖次数
57     a = 0 58     # 二等奖中奖次数
59     b = 0 60     # 三等奖中奖次数
61     c = 0 62     # 未中奖次数
63     d = 0 64     # 循环次数
65     e = 0 66     for i in range(1000): 67         e += 1
68         print('当前循环次数:', e) 69         result = lottery() 70         print('当前中奖结果:', result) 71         if (result == 1): 72             a += 1
73         elif (result == 2): 74             b += 1
75         elif (result == 3): 76             c += 1
77         else: 78             d += 1
79 80     print('一等奖中奖:', a, ',二等奖中奖次数:', b, ',三等奖中奖次数:', c, ',未中奖次数:', d) 81 82 # 会员制中奖测试方法
83 def test_vip(): 84     print('请输入您当前的会员等级:1.白银会员 2.黄金会员 3. 钻石会员') 85     level = input() 86     result = vip_lottery(int(level)) 87     if (result == 1): 88         print('恭喜您中了一等奖') 89     elif (result == 2): 90         print('恭喜您中了二等奖') 91     elif (result == 3): 92         print('恭喜您中了三等奖') 93     else: 94         print('未中奖,谢谢惠顾') 95 96 if __name__ == '__main__': 97     test_vip()
相关文章
相关标签/搜索