用python开发一个炸金花小游戏,注意别玩上瘾了~~(附完整源码)

关注+星标,每天学习Python新技能

因公众号更改推送规则,请点“在看”并加“星标”第一时间获取精彩技术分享

来源:网络

众所周知扑克牌可谓是居家旅行、桌面交友的必备道具,今天我们用 Python 来实现一个类似炸金花的扑克牌小游戏,先来看一下基本的游戏规则。

炸(诈)金花又叫三张牌,是在全国广泛流传的一种民间多人纸牌游戏。游戏使用一副除去大小王的扑克牌,共 4 个花色 52 张牌,各个玩家从中抽取 3 张牌,比较大小。各种牌型的大小顺序如下(按照全排列组合中出现的概率越小,牌型分数奖励越大):1、同花顺:三张同样花色且点数连续的牌,如红心2、红心3、红心4;2、豹子:三张点数一样的牌,如 AAA、222;3、顺子:三张点数连续的牌,如红心2、黑桃3、方块4;4、金花:三张同样花色的牌,如红心2、红心5、红心8;5、对子:两张点数一样的牌,如红心2、黑桃2;6、单张:2~10 < J < Q < K < A。以下概率截自百度百科:注:本文所述游戏规则与实际有所不同,主要基于对不同牌型的比较进行设计

一、游戏流程实现

1、准备扑克牌

开始游戏前,需要先生成一副满足要求的扑克牌,牌友们都知道,扑克牌有以下四种花色,每种花色有 A、2~10、J、Q、K 等 13 张牌。

suit = ["黑桃", "红心", "方块", "梅花"]   num = [str(i) for i in range(2, 11)] + ["J", "Q", "K", "A"]   

为了便于后续算分,先给每一个单张赋予相应的点数。

score_map = {}  # 单张点数映射表   for s in suit:       count = 2       for n in num:           score_map[f"{s}{n}"] = count           count += 1   

扑克牌点数预览如下:

score_map = {‘黑桃2’: 2, ‘黑桃3’: 3, ‘黑桃4’: 4, ‘黑桃5’: 5, ‘黑桃6’: 6, ‘黑桃7’: 7, ‘黑桃8’: 8, ‘黑桃9’: 9, ‘黑桃10’: 10, ‘黑桃J’: 11, ‘黑桃Q’: 12, ‘黑桃K’: 13, ‘黑桃A’: 14, ‘红心2’: 2, … }

2、玩家入场

以 p1、p2 等名称对玩家进行区分,我们先邀请 5 个玩家入场。

players = [f"p{i}" for i in range(1, 6)]   

3、发牌

将玩家和扑克牌列表作为参数,传入发牌器。发牌器在扑克牌中进行不放回抽取,为每个玩家随机抽取 3 张牌,并记下玩家名称及其对应牌组。

def get_pk_lst(pls, pks):       result = []       for p in pls:           pk = sample(pks, 3)           for _pk in pk:               pks.remove(_pk)           result.append({"name": p, "poker": pk})       return result      pokers = list(score_map.keys())  # 去掉大小王的一幅扑克   poker_grp = get_pk_lst(players, pokers)  # 发牌   

发牌预览如下:

result = [{‘name’: ‘p1’, ‘poker’: [‘方块5’, ‘梅花3’, ‘方块A’]}, {‘name’: ‘p2’, ‘poker’: [‘黑桃4’, ‘方块8’, ‘黑桃J’]}, {‘name’: ‘p3’, ‘poker’: [‘红心10’, ‘红心K’, ‘方块7’]}, {‘name’: ‘p4’, ‘poker’: [‘方块4’, ‘梅花6’, ‘方块J’]}, {‘name’: ‘p5’, ‘poker’: [‘红心5’, ‘梅花10’, ‘黑桃A’]}]

4、判断牌型及算分

在算分之前先按之前的映射字典,将 pk_lst 里的 3 张扑克牌转换成对应的点数。

n_lst = list(map(lambda x: score_map[x], pk_lst))  # 点数映射   

接下来截取花色部分的文本,利用集合去重后判断是否为三张同花。

same_suit = len(set([pk[:2] for pk in pk_lst])) == 1  # 是否同花色   

再对点数部分进行排序,与依靠点数的最值生成的顺序列表进行比较,判断是否为连续的点数。要注意的是,A23 与 QKA 一样被视作顺子。

continuity = sorted(n_lst) == [i for i in range(min(n_lst), max(n_lst) + 1)] or set(n_lst) == {14, 2, 3}  # 是否连续   

别忘了考虑对子和豹子的检查方式。

check = len(set(n_lst))  # 重复情况   

那么正式开始判断牌型和算分吧!首先是单张,非同花、非顺子、三张点数不一。得分以 3 个单张点数相加。

if not same_suit and not continuity and check == 3:       return sum(n_lst), "单张"   

其次是对子,非同花,有且仅有两张点数一致。得分中对于构成对子的部分给予 2 倍奖励。

if not same_suit and check == 2:       w = [i for i in n_lst if n_lst.count(i) == 2][0]       single = [i for i in n_lst if i != w][0]       return w*2*2 + single, "对子"   

金花,即同花而非顺子,给予 9 倍奖励。

if same_suit and not continuity:       return sum(n_lst)*9, "金花"   

顺子,即点数连续而非同花,给予 81 倍奖励。

if continuity and not same_suit:       return sum(n_lst)*81, "顺子"   

豹子,即三张点数一致,这不得刷个 666 嘛。

if check == 1:       return sum(n_lst)*666, "豹子"   

同花顺,同花色且点数连续,绝了,赌神一个技能 999 伤害。

if continuity and same_suit:       return sum(n_lst)*999, "同花顺"   

5、决出胜负

一组玩家、抽牌、算分、牌型记录如下:

pk_grp = [{‘name’: ‘p1’, ‘poker’: [‘方块5’, ‘梅花3’, ‘方块A’], ‘score’: 22, ‘type’: ‘单张’}, {‘name’: ‘p2’, ‘poker’: [‘黑桃4’, ‘方块8’, ‘黑桃J’], ‘score’: 23, ‘type’: ‘单张’}, {‘name’: ‘p3’, ‘poker’: [‘红心10’, ‘红心K’, ‘方块7’], ‘score’: 30, ‘type’: ‘单张’}, {‘name’: ‘p4’, ‘poker’: [‘方块4’, ‘梅花6’, ‘方块J’], ‘score’: 21, ‘type’: ‘单张’}, {‘name’: ‘p5’, ‘poker’: [‘红心5’, ‘梅花10’, ‘黑桃A’], ‘score’: 29, ‘type’: ‘单张’}]

利用 max 函数找出来谁是最棒的,公布名字!

best = max(pk_grp, key=lambda x: x["score"])["name"]   

赢家是------ p3

好啦,又可以开始下一场愉快的游戏了~

二、统计及源码

1、牌型统计

进行了 10 万场游戏并对各类牌型进行频率统计,可见与前述排列组合的计算所得概率基本一致。

Counter({'单张': 371856, '对子': 84773, '金花': 24833, '顺子': 16239, '豹子': 1179, '同花顺': 1120})   单张频率:74.37%   对子频率:16.95%   金花频率:4.97%   顺子频率:3.25%   豹子频率:0.24%   同花顺频率:0.22%   

2、牌局案例

各类牌型的局面和结果如下:

开牌结果------   {'name': 'p1', 'poker': ['方块5', '梅花3', '方块A'], 'score': 22, 'type': '单张'}   {'name': 'p2', 'poker': ['黑桃4', '方块8', '黑桃J'], 'score': 23, 'type': '单张'}   {'name': 'p3', 'poker': ['红心10', '红心K', '方块7'], 'score': 30, 'type': '单张'}   {'name': 'p4', 'poker': ['方块4', '梅花6', '方块J'], 'score': 21, 'type': '单张'}   {'name': 'p5', 'poker': ['红心5', '梅花10', '黑桃A'], 'score': 29, 'type': '单张'}   赢家是------   p3         开牌结果------   {'name': 'p1', 'poker': ['方块Q', '黑桃5', '黑桃K'], 'score': 30, 'type': '单张'}   {'name': 'p2', 'poker': ['黑桃2', '方块2', '红心10'], 'score': 18, 'type': '对子'}   {'name': 'p3', 'poker': ['梅花2', '黑桃4', '梅花J'], 'score': 17, 'type': '单张'}   {'name': 'p4', 'poker': ['红心K', '梅花7', '红心6'], 'score': 26, 'type': '单张'}   {'name': 'p5', 'poker': ['方块A', '方块6', '红心4'], 'score': 24, 'type': '单张'}   赢家是------   p1         开牌结果------   {'name': 'p1', 'poker': ['黑桃J', '黑桃5', '黑桃4'], 'score': 180, 'type': '金花'}   {'name': 'p2', 'poker': ['梅花7', '红心4', '梅花5'], 'score': 16, 'type': '单张'}   {'name': 'p3', 'poker': ['方块5', '黑桃9', '梅花10'], 'score': 24, 'type': '单张'}   {'name': 'p4', 'poker': ['黑桃Q', '梅花9', '黑桃10'], 'score': 31, 'type': '单张'}   {'name': 'p5', 'poker': ['红心9', '方块9', '红心A'], 'score': 50, 'type': '对子'}   赢家是------   p1         开牌结果------   {'name': 'p1', 'poker': ['方块8', '黑桃10', '方块9'], 'score': 2187, 'type': '顺子'}   {'name': 'p2', 'poker': ['梅花9', '红心Q', '黑桃3'], 'score': 24, 'type': '单张'}   {'name': 'p3', 'poker': ['方块A', '梅花K', '黑桃4'], 'score': 31, 'type': '单张'}   {'name': 'p4', 'poker': ['方块J', '红心J', '红心6'], 'score': 50, 'type': '对子'}   {'name': 'p5', 'poker': ['梅花5', '黑桃K', '方块3'], 'score': 21, 'type': '单张'}   赢家是------   p1         开牌结果------   {'name': 'p1', 'poker': ['黑桃Q', '黑桃8', '梅花6'], 'score': 26, 'type': '单张'}   {'name': 'p2', 'poker': ['红心3', '梅花3', '黑桃3'], 'score': 5994, 'type': '豹子'}   {'name': 'p3', 'poker': ['红心A', '红心6', '方块5'], 'score': 25, 'type': '单张'}   {'name': 'p4', 'poker': ['黑桃4', '梅花A', '方块2'], 'score': 20, 'type': '单张'}   {'name': 'p5', 'poker': ['梅花7', '黑桃6', '梅花8'], 'score': 1701, 'type': '顺子'}   赢家是------   p2         开牌结果------   {'name': 'p1', 'poker': ['黑桃5', '梅花9', '方块9'], 'score': 41, 'type': '对子'}   {'name': 'p2', 'poker': ['黑桃Q', '黑桃2', '红心Q'], 'score': 50, 'type': '对子'}   {'name': 'p3', 'poker': ['红心2', '黑桃7', '红心5'], 'score': 14, 'type': '单张'}   {'name': 'p4', 'poker': ['梅花3', '方块10', '黑桃A'], 'score': 27, 'type': '单张'}   {'name': 'p5', 'poker': ['黑桃9', '黑桃J', '黑桃10'], 'score': 29970, 'type': '同花顺'}   赢家是------   p5   

3、完整代码

`# @Seon   # 炸金花      from random import sample   from collections import Counter         def get_pk_lst(pls, pks):  # 发牌       result = []       for p in pls:           pk = sample(pks, 3)           for _pk in pk:               pks.remove(_pk)           result.append({"name": p, "poker": pk})       return result         def calculate(_score_map, pk_lst):  # 返回得分和牌型       n_lst = list(map(lambda x: _score_map[x], pk_lst))  # 点数映射       same_suit = len(set([pk[:2] for pk in pk_lst])) == 1  # 是否同花色       continuity = sorted(n_lst) == [i for i in range(min(n_lst), max(n_lst) + 1)] or set(n_lst) == {14, 2, 3}  # 是否连续       check = len(set(n_lst))  # 重复情况       if not same_suit and not continuity and check == 3:           return sum(n_lst), "单张"       if not same_suit and check == 2:           w = [i for i in n_lst if n_lst.count(i) == 2][0]           single = [i for i in n_lst if i != w][0]           return w*2*2 + single, "对子"       if same_suit and not continuity:           return sum(n_lst)*9, "金花"       if continuity and not same_suit:           return sum(n_lst)*81, "顺子"       if check == 1:           return sum(n_lst)*666, "豹子"       if continuity and same_suit:           return sum(n_lst)*999, "同花顺"         def compare(_score_map, pk_grp):  # 比大小       for p in pk_grp:           p["score"], p["type"] = calculate(_score_map, p["poker"])       print("开牌结果------")       for p in pk_grp:           print(p)       print("赢家是------")       best = max(pk_grp, key=lambda x: x["score"])["name"]       print(best)       return pk_grp         def show(_score_map, _players):   # 开局       pokers = list(_score_map.keys())       poker_grp = get_pk_lst(_players, pokers)       return compare(_score_map, poker_grp)         def start_game(_score_map, _players, freq=1):   # 游戏和统计       type_lst = []       for i in range(freq):           grp = show(_score_map, _players)           type_lst = type_lst + [t["type"] for t in grp]       c = Counter(type_lst)       print(c)       total = sum(c.values())       for item in c.items():           print(f"{item[0]}频率:{item[1]/total:.2%}")         if __name__ == '__main__':       # 准备扑克牌       suit = ["黑桃", "红心", "方块", "梅花"]       num = [str(i) for i in range(2, 11)] + ["J", "Q", "K", "A"]       score_map = {}  # 单张点数映射表       for s in suit:           count = 2           for n in num:               score_map[f"{s}{n}"] = count               count += 1       # 5个玩家入场       players = [f"p{i}" for i in range(1, 6)]       # 开始游戏       start_game(score_map, players, freq=100000)`      


![](https://mmbiz.qpic.cn/mmbiz/cZV2hRpuAPiaJQXWGyC9wrUzIicibgXayrgibTYarT3A1yzttbtaO0JlV21wMqroGYT3QtPq2C7HMYsvicSB2p7dTBg/640?wx_fmt=gif&wxfrom=5&wx_lazy=1&wx_co=1 "音符")

  

**长按或扫描下方二维码,免费**获取**** **Python公开课****和大佬打包整理的几百G的****学习资料****,内容包含但不限于Python电子书、教程、项目接单、源码等等**

![](https://mmbiz.qpic.cn/mmbiz_jpg/iaahNUMjJc7tfmwyuPKscwlibjPZMBZnVjO47uykuHH316Xuicsvic3xibKfSDWHYlacCF94M6Jauynu8uV3icC3qpHQ/640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1&wx_co=1)

**▲****扫描二维码-免费领取**




**推荐阅读**

*   [完整案例!Python + SQL 京东用户行为分析](http://mp.weixin.qq.com/s?__biz=MzU4NDY1Nzc4Mg==&mid=2247527662&idx=1&sn=f47d3e86b9ff8b15c6c5e6bc09c7f206&chksm=fd9452f7cae3dbe1dc5d6380afcaba7ef5d8d3c7c386c3eb9e86a4a50709b4f16e9d84e9cd21&scene=21#wechat_redirect)  
    
*   [用Python写了一个贪吃蛇大冒险小游戏](http://mp.weixin.qq.com/s?__biz=MzU4NDY1Nzc4Mg==&mid=2247527516&idx=1&sn=2abc30357f31e67eaf290a9a1953f4cb&chksm=fd945245cae3db53a5c0887dd32f6353ed7e556bd94b21a606e2f91583953b12a65d9fbf8bac&scene=21#wechat_redirect)  
    
*   [Python实用技巧:将 Excel转为PDF](http://mp.weixin.qq.com/s?__biz=MzU4NDY1Nzc4Mg==&mid=2247527492&idx=1&sn=64a1a5f9ee97f89d9b6f096a0e0c9879&chksm=fd94525dcae3db4b67bf2398a900310db2321bc27dd35857d879ef0c070f254f08f0923a67ce&scene=21#wechat_redirect)  
    
*   [四大游戏编程网站,边玩游戏,边学Python,拒绝枯燥快乐编程](http://mp.weixin.qq.com/s?__biz=MzU4NDY1Nzc4Mg==&mid=2247527491&idx=1&sn=26741a6b6464606e027a67b29b8f81f8&chksm=fd94525acae3db4cb2b4c14f49417fc51df6bfb7540887d9ce0c8c25898a42732bc6e3c1c7bc&scene=21#wechat_redirect)  
    

  


**点击下方安全链接前往获取**

**[CSDN大礼包:《Python入门&进阶学习资源包》免费分享](https://mp.weixin.qq.com/s/b5jwyLC8FsKhg6O8ynyPUA)**

### 👉**Python实战案例**👈

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

![图片](https://img-blog.csdnimg.cn/img_convert/c0b9c17420f1ca2e7de1d2538a3d2e24.jpeg)

![图片](https://img-blog.csdnimg.cn/img_convert/344eecb165bbae17b0e3cd094344dd85.png)

### **👉Python书籍和视频合集**👈

观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

![图片](https://img-blog.csdnimg.cn/img_convert/25f6366657e54205b390bfc027b15461.png)

### 👉**Python副业创收路线**👈

 ![图片](https://img-blog.csdnimg.cn/img_convert/bc473deaa930fc8d288d6471c9479098.png) 



 **这些资料都是非常不错的**,朋友们如果有需要《Python学习路线&学习资料》,**点击下方安全链接前往获取**

**[CSDN大礼包:《Python入门&进阶学习资源包》免费分享](https://mp.weixin.qq.com/s/b5jwyLC8FsKhg6O8ynyPUA)**

  

本文转自网络,如有侵权,请联系删除。
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值