網(wǎng)站充值 下模板aso排名優(yōu)化
眾所周知撲克牌可謂是居家旅行、桌面交友的必備道具,今天我們用 Python 來實現(xiàn)一個類似炸金花的撲克牌小游戲,先來看一下基本的游戲規(guī)則。
炸(詐)金花又叫三張牌,是在全國廣泛流傳的一種民間多人紙牌游戲。游戲使用一副除去大小王的撲克牌,共 4 個花色 52 張牌,各個玩家從中抽取
3
張牌,比較大小。各種牌型的大小順序如下(按照全排列組合中出現(xiàn)的概率越小,牌型分數(shù)獎勵越大):1、同花順:三張同樣花色且點數(shù)連續(xù)的牌,如紅心2、紅心3、紅心4;2、豹子:三張點數(shù)一樣的牌,如
AAA、222;3、順子:三張點數(shù)連續(xù)的牌,如紅心2、黑桃3、方塊4;4、金花:三張同樣花色的牌,如紅心2、紅心5、紅心8;5、對子:兩張點數(shù)一樣的牌,如紅心2、黑桃2;6、單張:2~10
< J < Q < K < A。以下概率截自百度百科:圖片注:本文所述游戲規(guī)則與實際有所不同,主要基于對不同牌型的比較進行設(shè)計
?
一、游戲流程實現(xiàn)
1、準備撲克牌
開始游戲前,需要先生成一副滿足要求的撲克牌,牌友們都知道,撲克牌有以下四種花色,每種花色有 A、2~10、J、Q、K 等 13 張牌。
suit = ["黑桃", "紅心", "方塊", "梅花"]
num = [str(i) for i in range(2, 11)] + ["J", "Q", "K", "A"]
為了便于后續(xù)算分,先給每一個單張賦予相應(yīng)的點數(shù)。
score_map = {} # 單張點數(shù)映射表
for s in suit:count = 2for n in num:score_map[f"{s}{n}"] = countcount += 1
撲克牌點數(shù)預(yù)覽如下:
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 等名稱對玩家進行區(qū)分,我們先邀請 5 個玩家入場。
players = [f"p{i}" for i in range(1, 6)]
3、發(fā)牌
將玩家和撲克牌列表作為參數(shù),傳入發(fā)牌器。發(fā)牌器在撲克牌中進行不放回抽取,為每個玩家隨機抽取 3 張牌,并記下玩家名稱及其對應(yīng)牌組。
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) # 發(fā)牌
發(fā)牌預(yù)覽如下:
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 張撲克牌轉(zhuǎn)換成對應(yīng)的點數(shù)。
n_lst = list(map(lambda x: score_map[x], pk_lst)) # 點數(shù)映射
?接下來截取花色部分的文本,利用集合去重后判斷是否為三張同花。
same_suit = len(set([pk[:2] for pk in pk_lst])) == 1 # 是否同花色
再對點數(shù)部分進行排序,與依靠點數(shù)的最值生成的順序列表進行比較,判斷是否為連續(xù)的點數(shù)。要注意的是,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} # 是否連續(xù)
別忘了考慮對子和豹子的檢查方式。
check = len(set(n_lst)) # 重復(fù)情況
那么正式開始判斷牌型和算分吧!首先是單張,非同花、非順子、三張點數(shù)不一。得分以 3 個單張點數(shù)相加。
if not same_suit and not continuity and check == 3:return sum(n_lst), "單張"
其次是對子,非同花,有且僅有兩張點數(shù)一致。得分中對于構(gòu)成對子的部分給予 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, "金花"
順子,即點數(shù)連續(xù)而非同花,給予 81 倍獎勵。
if continuity and not same_suit:return sum(n_lst)*81, "順子"
豹子,即三張點數(shù)一致,這不得刷個 666 嘛。
if check == 1:return sum(n_lst)*666, "豹子"
同花順,同花色且點數(shù)連續(xù),絕了,賭神一個技能 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 函數(shù)找出來誰是最棒的,公布名字!
best = max(pk_grp, key=lambda x: x["score"])["name"]
?贏家是:p3
好啦,又可以開始下一場愉快的游戲了~
二、統(tǒng)計及源碼
1、牌型統(tǒng)計
進行了 10 萬場游戲并對各類牌型進行頻率統(tǒng)計,可見與前述排列組合的計算所得概率基本一致。
Counter({‘單張’: 371856, ‘對子’: 84773, ‘金花’: 24833, ‘順子’: 16239, ‘豹子’: 1179, ‘同花順’: 1120})
單張頻率:74.37%
對子頻率:16.95%
金花頻率:4.97%
順子頻率:3.25%
豹子頻率:0.24%
同花順頻率:0.22%
2、牌局案例
各類牌型的局面和結(jié)果如下:
開牌結(jié)果------
{'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開牌結(jié)果------
{'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開牌結(jié)果------
{'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開牌結(jié)果------
{'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開牌結(jié)果------
{'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開牌結(jié)果------
{'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): # 發(fā)牌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)) # 點數(shù)映射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} # 是否連續(xù)check = len(set(n_lst)) # 重復(fù)情況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("開牌結(jié)果------")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): # 游戲和統(tǒng)計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 = {} # 單張點數(shù)映射表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)
三、零基礎(chǔ)小白的Python學(xué)習(xí)資源總結(jié)
如果你也喜歡編程,想通過學(xué)習(xí)Python轉(zhuǎn)行、做副業(yè)或者提升工作效率,我也為大家整理了一份【最新全套Python學(xué)習(xí)資料】一定對你有用!
對于0基礎(chǔ)小白入門:
如果你是零基礎(chǔ)小白,想快速入門Python是可以考慮的!
1、學(xué)習(xí)時間相對較短,學(xué)習(xí)內(nèi)容更全面更集中
2、可以找到適合自己的學(xué)習(xí)方案
這份資料包含:Python安裝包+激活碼、Python web開發(fā),Python爬蟲,Python數(shù)據(jù)分析,人工智能、機器學(xué)習(xí)等教程,帶你從零開始系統(tǒng)性的學(xué)好Python!
點擊免費領(lǐng)取《CSDN大禮包》:
最新全套【Python入門到進階資料 & 實戰(zhàn)源碼 & 安裝工具】
https://mp.weixin.qq.com/s/9IuSexhanYZ1TMAF1MZIhw
1、Python所有方向的學(xué)習(xí)路線
Python所有方向路線就是把Python常用的技術(shù)點做整理,形成各個領(lǐng)域的知識點匯總,它的用處就在于,你可以按照上面的知識點去找對應(yīng)的學(xué)習(xí)資源,保證自己學(xué)得較為全面。
2、Python課程視頻
我們在看視頻學(xué)習(xí)的時候,不能光動眼動腦不動手,比較科學(xué)的學(xué)習(xí)方法是在理解之后運用它們,這時候練手項目就很適合了。
3、全套PDF電子書
書籍的好處就在于權(quán)威和體系健全,剛開始學(xué)習(xí)的時候你可以只看視頻或者聽某個人講課,但等你學(xué)完之后,你覺得你掌握了,這時候建議還是得去看一下書籍,看權(quán)威技術(shù)書籍也是每個程序員必經(jīng)之路。
4、清華編程大佬出品《漫畫看學(xué)Python》
用通俗易懂的漫畫,來教你學(xué)習(xí)Python,讓你更容易記住,并且不會枯燥乏味。
5、Python實戰(zhàn)案例
光學(xué)理論是沒用的,要學(xué)會跟著一起敲,要動手實操,才能將自己的所學(xué)運用到實際當(dāng)中去,這時候可以搞點實戰(zhàn)案例來學(xué)習(xí)。
6、互聯(lián)網(wǎng)企業(yè)面試真題
我們學(xué)習(xí)Python必然是為了找到高薪的工作,下面這些面試題是來自阿里、騰訊、字節(jié)等一線互聯(lián)網(wǎng)大廠最新的面試資料,并且有阿里大佬給出了權(quán)威的解答,刷完這一套面試資料相信大家都能找到滿意的工作。
這份完整版的Python全套學(xué)習(xí)資料已經(jīng)上傳至CSDN官方,朋友們?nèi)绻枰梢渣c擊下方鏈接費獲取【保證100%免費】
點擊免費領(lǐng)取《CSDN大禮包》:
最新全套【Python入門到進階資料 & 實戰(zhàn)源碼 & 安裝工具】
https://mp.weixin.qq.com/s/9IuSexhanYZ1TMAF1MZIhw
以上全套資料已經(jīng)為大家打包準備好了,希望對正在學(xué)習(xí)Python的你有所幫助!
如果你覺得這篇文章有幫助,可以點個贊呀~
我會堅持每天更新Python相關(guān)干貨,分享自己的學(xué)習(xí)經(jīng)驗幫助想學(xué)習(xí)Python的朋友們少走彎路!