众所周知扑克牌可谓是居家旅行、桌面交友的必备道具,今天我们用 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 r