用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 = 2for n in num:score_map[f"{s}{n}"] = countcount += 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 resultpokers = 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 万场游戏并对各类牌型进行频率统计,可见与前述排列组合的计算所得概率基本一致。另外,搜索公众号Linux就该这样学后台回复“猴子”,获取一份惊喜礼包。

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 Counterdef 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 resultdef 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_grpdef 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 = 2for n in num:score_map[f"{s}{n}"] = countcount += 1# 5个玩家入场players = [f"p{i}" for i in range(1, 6)]# 开始游戏start_game(score_map, players, freq=100000)
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/68414.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【算法与数据结构】106、LeetCode从中序与后序遍历序列构造二叉树

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;首先我们要知道后序遍历数组的最后一个元素必然是根节点&#xff0c;然后根据根节点在中序遍历数组中的…

postgres源码解析55 Brin Index--2(brinbuild流程)

上一篇讲解了brin index的基本概念以及页布局postgres源码解析54 Brin Index–1&#xff0c;后续会从源码角度对索引的构建、维护等方面进行深入讲解。 1 关键数据结构 2 brinbuild执行流程图 3 brinbuild 函数详解 1 首先调用brin_matepage_init初始化brin meta元数据页&…

【0904作业】QT 完成登陆界面跳转到聊天室+完成学生管理系统的查找和删除功能

一、完成登陆界面跳转到聊天室 1> 项目结构 2> 源码 ① .pro ②main #include "mywnd.h" #include"chatCli.h" #include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);MyWnd w;w.show();Form f;QObject::co…

Lite transformer

图片以及思想来源请参考论文 Lite Transformer with Long-Short Range Attention 瓶颈结构&#xff08;bottleneck&#xff09;是否真的有效 注意力机制被广泛应用在诸多领域&#xff0c;包括自然语言处理&#xff0c;图像处理和视频处理。它通过计算所有输入元素的点积来建模…

低代码平台:IVX 重新定义编程

目录 &#x1f36c;一、写在前面 &#x1f36c;二、低代码平台是什么 &#x1f36c;三、为什么程序员和技术管理者不太可能接受“低代码”平台&#xff1f; &#x1f36d;1、不安全&#xff08;锁定特性&#xff09; &#x1f36d;2、不信任 &#x1f36c;四、IVX低代码平台 &a…

《阿里巴巴 Java 开发手册》(一)命名风格

《阿里巴巴 Java 开发手册》 一、编程规约(一)命名风格(二)常量定义(三)代码格式 一、编程规约 (一)命名风格 (二)常量定义 (三)代码格式

LabVIEW开发感应电机在线匝间短路故障诊断系统

LabVIEW开发感应电机在线匝间短路故障诊断系统 工业中使用的超过85%的电动机是三相感应电动机。它们因其可靠性、设计便利性、高性能和过载能力而被广泛用于不同的应用&#xff0c;例如制造、加工、电力系统、运输等。无论它们的能力如何&#xff0c;它们都被认为是现代工业学…

Unity通过偏移UV播放序列帧动画

大家好&#xff0c;我是阿赵。   在Unity引擎里面用shader播放序列图&#xff0c;估计很多人都有用到了&#xff0c;我自己而已写过好几个版本。这里大概介绍一下。 一、原理 先说目的&#xff0c;我现在有一张这样的图片&#xff1a; 这张图片上面&#xff0c;有9个格子&a…

使用errors.Wrapf()代替log.Error()

介绍不同语言的错误处理机制: Error handling patterns[1] Musings about error handling mechanisms in programming languages[2] 项目中 main调func1&#xff0c;func1调取func2... 这样就会出现很多的 if err ! nil { log.Printf()} , 在Kibana上查看时会搜到多条日志, 需要…

美妆+七人拼团模式:如何打造新型社交电商营销方式

美妆是一个充满竞争和创新的行业&#xff0c;要想在市场上获得优势&#xff0c;就需要不断寻找新的营销方式&#xff0c;吸引和留住消费者。七人拼团模式就是一种结合了社交电商和拼购玩法的新型商业模式&#xff0c;它可以利用社交网络的裂变效应&#xff0c;增加品牌曝光度和…

vue+elementUI el-select 自定义搜索逻辑(filter-method)

下拉列表的默认搜索是搜索label显示label,我司要求输入id显示label名称 <el-form-item label"部门&#xff1a;"><el-select v-model"form.region1" placeholder"请选择部门" filterable clearable:filter-method"dataFilter&qu…

AndroidTV端:酒店扫码认证投屏DLNA

被老板叼了几次了&#xff0c;最近实在忍不了&#xff0c;准备离职&#xff1b; 但是担心离职后长时间没有办法找到工作 就想贡献一套平时琢磨出来的程序&#xff0c;请各位有能力的话带我熬过这凛冽的寒冬。 目前写出来的&#xff0c;有三个端&#xff1a;安卓TV端&#xf…

准备HarmonyOS开发环境

引言 在开始 HarmonyOS 开发之前&#xff0c;需要准备好开发环境。本章将详细指导你如何安装 HarmonyOS SDK、配置开发环境、创建 HarmonyOS 项目。 目录 安装 HarmonyOS SDK 配置开发环境 创建 HarmonyOS 项目 总结 1. 安装 HarmonyOS SDK HarmonyOS SDK 是开发 Harmo…

【Selenium2+python】自动化unittest生成测试报告

前言 批量执行完用例后&#xff0c;生成的测试报告是文本形式的&#xff0c;不够直观&#xff0c;为了更好的展示测试报告&#xff0c;最好是生成HTML格式的。 unittest里面是不能生成html格式报告的&#xff0c;需要导入一个第三方的模块&#xff1a;HTMLTestRunner 一、导…

leetcode1288. 删除被覆盖区间(java)

删除被覆盖区间 题目描述贪心法代码演示 题目描述 难度 - 中等 leetcode1288. 删除被覆盖区间 给你一个区间列表&#xff0c;请你删除列表中被其他区间所覆盖的区间。 只有当 c < a 且 b < d 时&#xff0c;我们才认为区间 [a,b) 被区间 [c,d) 覆盖。 在完成所有删除操作…

Docker使用数据卷挂载进行数据存储与共享

一、挂载和数据卷 在 Docker 中&#xff0c;挂载&#xff08;Mounting&#xff09;和数据卷&#xff08;Data Volumes&#xff09;是用于在容器和宿主机之间共享数据的机制。 挂载&#xff1a;将宿主机文件系统中的目录或文件与容器中的目录或文件进行关联的过程。数据卷&…

收入下降,亏损扩大,利润率急剧恶化,蔚来仍充满风险

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 蔚来第二季度财报分析 猛兽财经从蔚来&#xff08;NIO&#xff09;2023年第二季度财报中&#xff0c;获得的最大收获并不是该公司的收入下降或亏损扩大&#xff0c;而是由于价格竞争加剧&#xff0c;中国电动汽车行业整体上…

什么是安全运营中心(SOC),应该了解什么

安全运营中心&#xff08;SOC&#xff09; 是一种企业监视和警报设施&#xff0c;可帮助组织检测安全威胁、监视安全事件和分析性能数据以改进公司运营。 什么是安全运营中心&#xff08;SOC&#xff09; 安全运营中心&#xff08;SOC&#xff09;是一个中央监视和监视中心&a…

第二次作业

1.编写脚本for1.sh,使用for循环创建20账户&#xff0c;账户名前缀由用户从键盘输入&#xff0c;账户初始密码由用户输入&#xff0c;例如: test1、test2、test3、.....、 test10 编写脚本for1.sh 执行脚本&#xff1a;bash for.sh 2&#xff0c;编写脚本for2.sh,使用for循环,通…

模糊测试面面观 | 模糊测试是如何发现异常情况的?

协议模糊测试是一种用于评估通信协议、文件格式和API实现系统安全性和稳定性的关键技术。在模糊测试过程中&#xff0c;监视器扮演着关键角色&#xff0c;它们能够捕获异常情况、错误响应、资源利用等&#xff0c;为测试人员提供有价值的信息&#xff0c;有助于发现潜在漏洞和问…