用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.rhkb.cn/news/123705.html

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

相关文章

新风机是什么?

新风机是空气净化设备中的一种&#xff0c;能够将新鲜外界空气引入室内&#xff0c;同时将室内的污浊空气排出去&#xff0c;从而实现室内空气的循环和净化。新风机主要是由风机、过滤器、热交换器和控制面板等部分组成。 风机&#xff1a;新风机中风机是一个非常重要的部件&am…

windows环境搭建ELK

目录 资源下载&#xff08;8.9.1&#xff09; ES安装、注册、使用 Kibana安装、注册、使用 Logstash安装、注册、使用 Filebeat安装、使用&#xff08;如果只有一个数据流&#xff0c;则不需要使用filebeat&#xff0c;直接上logstash即可&#xff09; 资源下载&#xff0…

Vivado 添加FPGA开发板的Boards file的添加

1 digilent board file 下载地址 下载地址 &#xff1a; https://github.com/Digilent/vivado-boards 2 下载后 3 添加文件到 vivado 安装路径 把文件复制到 Vivado\2019.1\data\boards\board_files4 创建工程查看是否安装成功

​Vue + Element UI前端篇(二):Vue + Element 案例 ​

Vue Element UI 实现权限管理系统 前端篇&#xff08;二&#xff09;&#xff1a;Vue Element 案例 导入项目 打开 Visual Studio Code&#xff0c;File --> add Folder to Workspace&#xff0c;导入我们的项目。 安装 Element 安装依赖 Element 是国内饿了么公司提…

MySQL的故事——创建高性能的索引

创建高性能的索引 文章目录 创建高性能的索引一、索引基础二、索引的优点三、高性能的索引策略 一、索引基础 要理解MySQL中索引是如何工作的&#xff0c;最简单的方法就是去看看一本书的“索引 ”部分&#xff1a;如果在一本书中找到某个特定主题&#xff0c;一般会先看书的“…

【消息中间件】详解三大MQ:RabbitMQ、RocketMQ、Kafka

作者简介 前言 博主之前写过一个完整的MQ系列&#xff0c;包含RabbitMQ、RocketMQ、Kafka&#xff0c;从安装使用到底层机制、原理。专栏地址&#xff1a; https://blog.csdn.net/joker_zjn/category_12142400.html?spm1001.2014.3001.5482 本文是该系列的清单综述&#xf…

RunnerGo怎么做性能测试

RunnerGo是一个功能强大&#xff0c;使用简单的性能测试平台&#xff0c;它基于go语言开发&#xff0c;支持接口管理、自动化测试、性能测试等功能。 RunnerGo有什么特点 支持并发模式、错误率模式、阶梯模式、每秒请求数模式、响应时间模式等多种压测模式&#xff0c;支持自…

.NET之后,再无大创新

回想起来&#xff0c;2001年发布的.NET已经是距离最近的一次软件开发技术的整体创新了&#xff0c;后续的新技术就没有在各个端都这么成功的了。.NET是Windows平台下软件开发技术的巨大变革。在此之前&#xff0c;有VB、C&#xff08;MFC&#xff09;、JSP&#xff0c;在此之后…

数学建模-大模型的对比

引用老哥数学建模视频 【ChatGPT 4.0】在数学建模中的应用&#xff01;算法Matlab写作&#xff0c;全面测评六款大模型软件&#xff0c;直接使用&#xff01; 哪些问题可以问GPT 一、算法应用 1帮我总结一下数学建模有哪些预测类算法&#xff1f; 2灰色预测模型级比检验是什么…

递归算法学习——N皇后问题,单词搜索

目录 ​编辑 一&#xff0c;N皇后问题 1.题意 2.解释 3.题目接口 4.解题思路及代码 二&#xff0c;单词搜索 1.题意 2.解释 3.题目接口 4.思路及代码 一&#xff0c;N皇后问题 1.题意 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上…

TCP/IP基础

前言&#xff1a; TCP/IP协议是计算机网络领域中最基本的协议之一&#xff0c;它被广泛应用于互联网和局域网中&#xff0c;实现了不同类型、不同厂家、运行不同操作系统的计算机之间的相互通信。本文将介绍TCP/IP协议栈的层次结构、各层功能以及数据封装过程&#xff0c;帮助您…

【计算机网络】https协议

目录 概念的准备 什么是加密 为什么需要加密 常见的加密方式 对称加密 非对称加密 数据摘要(数字指纹) 数字签名 https的工作过程 方案一&#xff1a;只使用对称加密 方案二&#xff1a;只使用非对称加密 方案三&#xff1a;双方都采用非对称加密 方案四&#xff…

Vue3实现可视化拖拽标签小程序

介绍 实现功能&#xff1a;可视化标签拖拽&#xff0c;双击标签可修改标签内容 HTML结构 <div class"box" v-move><div class"header">标签1</div><div dblclick"startEditing" v-if"!isEditing">{{content…

开始投简历了

歇了好长时间&#xff0c;也该开始找点事情折腾了。 第一周基本上是没有什么太多的消息&#xff0c;大部分情况就是收到回复的邮件说你很优秀&#xff0c;希望下次合作这种礼节性的拒绝邮件。 给人有点感觉都是在忽悠&#xff0c;有点感觉现在的公司一边到处拒绝&#xff0c;…

实现Map批量赋值,我只需24秒搞定!

函数的功能是将一组键值对批量赋值给Map中的键。在Java中&#xff0c;通常使用Map的put方法逐个将键值对赋值给Map&#xff0c;但在某些场景下&#xff0c;可能需要一次性将多个键值对赋值给Map。 函数功能&#xff1a;Map批量赋值 参数1&#xff1a;参数名称&#xff1a;targ…

K8S自动化运维容器Docker集群

K8S&#xff1a;K8S自动化运维容器化(Docker)集群 一.k8s概述 1.k8s是什么 &#xff08;1&#xff09;K8S全程为Kubernetes&#xff0c;由于K到S直接有8个字母简称为K8S。 &#xff08;2&#xff09;版本&#xff1a;目前一般是1.18~1.2.0&#xff0c;后续可能会到1.24-1.2…

机器学习与数据分析

【数据清洗】 异常检测 孤立森林&#xff08;Isolation Forest&#xff09;从原理到实践 效果评估&#xff1a;F-score 【1】 保护隐私的时间序列异常检测架构 概率后缀树 PST – &#xff08;异常检测&#xff09; 【1】 UEBA架构设计之路5&#xff1a; 概率后缀树模型 【…

Spring 怎么解决循环依赖的呢?

Spring 怎么解决循环依赖 什么是循环依赖那 Spring 怎么解决循环依赖的呢&#xff1f;为什么要三级缓存&#xff1f;⼆级不⾏吗&#xff1f; 什么是循环依赖 Spring 循环依赖&#xff1a;简单说就是自己依赖自己&#xff0c;或者和别的 Bean 相互依赖。 只有单例的 Bean 才存在…

【肝素··】

Recent advances in the management of venous thromboembolism Korean J Hematol 2010;45:8-13 Serpin Structure, Mechanism, and Function-2002 糖胺聚糖 凝血 Fibrinolysis | Detailed Pedia

计算机视觉的应用13-基于SSD模型的城市道路积水识别的应用项目

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用13-基于SSD模型的城市道路积水识别的应用项目。今年第11号台风“海葵”后部云团的影响&#xff0c;福州地区的降雨量突破了历史极值&#xff0c;多出地方存在严重的积水。城市道路积水是造成交通拥…