首頁 > 軟體

利用Python編寫簡易版德州撲克小遊戲

2022-03-24 19:00:38

德州撲克簡要介紹

什麼是德州撲克

德州撲克不知道大家是否玩過,它是起源於美國的得克薩斯州的一種博弈類卡牌遊戲,英文名叫做Texas Hold’em Poker。玩法上又分為常規桌(Cash, 現金局),單桌賽(SNG)和多桌錦標賽(MTT)。雖然撲克種類繁多,但基本的撲克規則通常保持一致。它是一種考驗心態與謀略的遊戲。

遊戲規則簡要介紹

一、使用道具

一副標準撲克牌去掉大小王后的52張牌進行遊戲。

二、遊戲人數

一般2-10個玩家,個別情況有12個玩家的。

三、遊戲目的

贏取其他玩家籌碼

四、下注宗旨

玩家之間同時繼續看牌或比牌需要下同樣注額籌碼,籌碼不足的玩家all-in全下後可以看到底並參與比牌。

五、發牌下注

發牌一般分為5個步驟,分別為,

Perflop——先下大小盲注,然後給每個玩家發2張底牌,大盲注後面第一個玩家選擇跟注、加註或者蓋牌放棄,按照順時針方向,其他玩家依次表態,大盲注玩家最後表態,如果玩家有加註情況,前面已經跟注的玩家需要再次表態甚至多次表態。

Flop——同時發三張公牌,由小盲注開始(如果小盲注已蓋牌,由後面最近的玩家開始,以此類推),按照順時針方向依次表態,玩家可以選擇下注、加註、或者蓋牌放棄。

Turn——發第4張牌,由小盲注開始,按照順時針方向依次表態。

River——發第五張牌,由小盲注開始,按照順時針方向依次表態,玩家可以選擇下注、加註、或者蓋牌放棄。

比牌——經過前面4輪發牌和下注,剩餘的玩家開始亮牌比大小,成牌最大的玩家贏取池底。

六、比牌方法

用自己的2張底牌和5張公共牌結合在一起,選出5張牌,不論手中的牌使用幾張(甚至可以不用手中的底牌),湊成最大的成牌,跟其他玩家比大小。

比牌先比牌型,大的牌型大於小的牌型,牌型一般分為10種,從大到小為:

德州撲克遊戲的python實現過程

遊戲初始化

#呼叫random庫中的sample函數,用於從卡牌堆中隨機抽取卡牌
from random import sample

#利用列表記憶卡牌的花色與數位
color = ['黑桃','紅桃','梅花','方塊']
number = ['2','3','4','5','6','7','8','9','10','J','Q','K','A']

匯入random庫中的sample函數,後續用於從卡牌堆中隨機抽取卡牌。同時利用列表分別將卡牌的顏色與數位儲存在color與number中。

#PokerGenerator函數用於生成一組卡牌
def PokerGenerator():
    #將卡牌儲存於列表中
    Poker = []
    # 用字典表示卡牌,在Poker列表中新增52張空白的卡牌
    for i in range(0,52):
        t = {'數位':0,'花色':''}    
        Poker.append(t)
    #對每張卡牌進行賦值,每種花色各有13種花色,共四種花色,52張卡牌。  
    for i in range(0,52):
        Poker[i].update({'數位':number[i%13],'花色':color[i//13]})  
    #將儲存有52張卡牌的列表Poker返回
    return Poker

函數PokerGenerator用於生成一副新的撲克牌,德州撲克所採用的撲克牌標準牌組,包含四種花色(‘黑桃’,‘紅桃’,‘梅花’,‘方塊’),每種花色有’2’到’A’等13張卡牌,共52張撲克,不包含大小王。

#根據玩家人數分發卡牌
def Pokerinitial(playersum):
    Playerpoker = []
    Poker = PokerGenerator()#初始化一副新的卡牌
    num = 52
    
    for i in range(0,playersum):
        Pripoker = sample(Poker,2)#從卡牌中隨機抽取兩張卡牌作為一名玩家的手牌
        Playerpoker.append(Pripoker)#所抽取的卡牌以元組形式假加入Playerpoker列表中,以Playerpoker的下標序號代表玩家的序號
        #將每位玩家所抽取的卡牌從卡牌堆中刪除,即實現不放回抽樣
        for n in [0,1]:
            for m in range(0,num):
                if Poker[m] == Pripoker[n]:
                    del Poker[m]
                    num -=1
                    break               
                
    Publicpoker = sample(Poker,3)#從牌堆中再抽取三張牌作為公共牌
    #將所抽取的公共牌從牌堆中刪除
    for n in [0,1,2]:
            for m in range(0,num):
                if Poker[m] == Publicpoker[n]:
                    del Poker[m]
                    num -=1
                    break
    #將每位玩家的手牌與公共牌輸出顯示
    for i in range(0,playersum):
        print("玩家 %d"%(i+1)+":牌1:"+str(Playerpoker[i][0])+"  牌2:"+str(Playerpoker[i][1]))
        print("")
        
    print("")
    print("")    
    print("公共牌: "+str(Publicpoker)+"   ")
    
    return [Playerpoker,Poker,Publicpoker]#將玩家手牌,剩餘的牌堆,公共牌組返回

給每位玩家分發兩張手牌,分發遊戲開始時的三張公共牌,並將每位玩家的手牌情況與公共情況輸出顯示,利用字典表示撲克牌。

評選贏家

實現德州撲克最關鍵的一步便是計算出那位玩家的手牌最大,確定最終的贏家,若最終贏家有多位則平分獎池。我用0到8等9個數位分別代表高牌到同花順等四個等級,我不專門為皇家同花順列一個等級,若場上同時出現兩個同花順,則根據同花順中最大的卡牌數位來確定贏家,接下來開始介紹判斷各種手牌類別的方法。

#判斷玩家的牌與公共牌是否構成順子
def judgestraight(finalpoker):
    result = [0, 0]#用於儲存結果,result[0]中儲存此位玩家最好的五張牌的類別,從高牌到皇家同花順編號為0到9。result[1]儲存當前開組中數位最大的牌
    pokernum = []#記憶卡牌的數位
    for i in range(0, len(finalpoker)):
        pokernum.append(number.index(finalpoker[i]['數位']))
    pokernum.sort()#將卡牌號碼從小到大進行排序
    #判斷玩家卡牌與公共卡牌的組合是否能構成順子
    maxp = minp = 0
    for i in range(1, len(finalpoker)):
        if (pokernum[i - 1] + 1) == pokernum[i]:
            maxp = i
        else:
            minp = i
        if (maxp - minp) == 4:
            result[0] = 4
            result[1] = max(pokernum[minp:maxp + 1])

    return result

judgestraight函數用於判斷玩家手牌與五張公共牌是否能構成順子,需要輸入引數finalpoker。finalpoker應接受一個列表物件,其內應包含玩家手牌與最終的公共牌,總計7張牌。而後判斷其中是否有順子,並將判斷結果返回。結果中包含了兩個資訊:result[0]若為4則表明其內包含有順子,為0則不包含。若包含順子result[1]中會儲存順子中最大的卡牌數位。

#判斷卡組中是否存在同花
def judgeflush(finalpoker):
    result = [0, 0]
    pokernum = []
    flush = []#用於儲存相同花色的卡牌

    while len(finalpoker) >= 5:
        #抽出卡組中同花色的卡牌
        flush.append(finalpoker[0])
        for i in range(1, len(finalpoker)):
            if finalpoker[i]['花色'] == finalpoker[0]['花色']:
                flush.append(finalpoker[i])
            #若同花色卡牌不少於五張,那麼卡組存在同花
            if len(flush) >= 5:
                result[0] = 5
                for ele in flush:
                    pokernum.append(number.index(ele['數位']))
                result[1] = max(pokernum)
        for ele in flush:
            finalpoker.remove(ele)
        flush.clear()
    return result

judgeflush函數用於判斷玩家的手牌中是否包含有同花,並將結果返回。同上,judgestraight函數所返回的結果包含兩個資訊,玩家的手牌與公共拍的組合中是否包含有同花,若有同花則同時將同花中的最大數位返回。

#判斷卡組中是否存在四條、三條、兩對或一對
def judgesame(finalpoker):
    result = [0, 0]
    four = -1   #記錄卡組中是否存在四條
    three = -1  #記錄卡組中是否存在三條
    two = [-1, -1] #記錄卡組中是否存在兩對與一對

    count = 1
    pokernum = []
    bottom = 0
    #將卡組的所有卡牌號儲存進pokernum中,並進行排序
    for i in range(0, len(finalpoker)):
        pokernum.append(number.index(finalpoker[i]['數位']))
    pokernum.sort()
    #判斷卡組中是否存在四條、三條、兩對或一對等,並將所對應最大的卡牌數位進行儲存
    for i in range(1, len(finalpoker)):
        if pokernum[i] == pokernum[bottom]:
            count += 1
        else:
            if count == 2:
                if pokernum[bottom] > min(two):
                    numid = two.index(min(two))
                    two[numid] = pokernum[bottom]
            if count == 3:
                if pokernum[bottom] > three:
                    three = pokernum[bottom]
            if count == 4:
                four = pokernum[bottom]

            bottom = i
            count = 1
    #判斷卡組中所存在的最大的組合牌型別
    if four >= 0:
        result[0] = 7
        result[1] = four
    elif three >= 0 and max(two) >= 0:
        result[0] = 6
        t = three * 10 + max(two)
        result[1] = t
    elif three >= 0:
        result[0] = 3
        result[1] = three
    elif min(two) >= 0:
        result[0] = 2
        result[1] = max(two)
    elif max(two) >= 0:
        result[0] = 1
        result[1] = max(two)

    return result

這個函數相較於上面兩個函數相對長很多,因為它一個函數實現了三個功能,判斷玩家手牌與公共牌的組合中是否含有一對、兩對、三條或四條。與上述函數功能相似,judgesame會判斷所接受卡組中是否含有上述四種情況,若有則將等級最高的情況返回,同時將該情況中所含最大的卡牌數位返回。

#計算出玩家所持卡組中最大的組合牌型別
def computeresult(Playerpoker, Publicpoker):
    finalresult = [0, 0]
    finalpoker = []
    finalpoker = Playerpoker + Publicpoker
    a = finalpoker.copy()
    b = finalpoker.copy()
    c = finalpoker.copy()
    #分別儲存同花、順子、四條、三條(即數位相同的個數與情況)等的判斷結果
    result_1 = judgeflush(a)
    result_2 = judgestraight(b)
    result_3 = judgesame(c)
    #判斷是否是同花順
    if result_1[0] != 0 and result_2[0] != 0:
        finalresult[0] = 8
        finalresult[1] = result_2[1]
    #若不是同花順,則判斷玩家手牌與公共牌所在組成的最大卡組種類
    else:
        t_0 = result_1[0]
        t_1 = result_1[1]
        if result_2[0] > t_0:
            t_0 = result_2[0]
            t_1 = result_2[1]
        if result_3[0] > t_0:
            t_0 = result_3[0]
            t_1 = result_3[1]
    #確定最終結果,即玩家所擁有的最大卡牌種類
    finalresult[0] = t_0
    finalresult[1] = t_1

    return finalresult

我最終利用computeresult函數計算出每位玩家最終所擁有的最高等級卡組。在此函數中我分別呼叫了以上三個函數,通過比較得出玩家所擁有的最高等級卡組,並將結果返回。

遊戲主題函數

我們編寫的函數已能夠實現遊戲初始化與遊戲結果的計算,接下來我們便利用以上函數編寫德州撲克遊戲的真正的主體。

#遊戲函數主體
def gamestart(playersum):
    finalresult = []#用於儲存每個玩家的最大手牌
    [playerpoker,Poker,Publicpoker] = Pokerinitial(playersum)#根據玩家數初始化一副卡牌,並給每位玩家分發兩張手牌,並分發初始的三張公共牌
    playerlist = list(range(1,playersum+1))#記錄每輪迴合過後還剩下的玩家
    playerlist_t = []
    Playerpoker = []
    
    while len(Publicpoker) < 5 and len(playerlist) > 1:#當公共牌數為5或僅剩一個玩家時,遊戲結束進行結算
        tag = 0 #識別符號,標註所輸入的繼續遊戲的玩家是否有誤,若有誤則重新輸入
        playerkeep = input("請輸入繼續遊戲的玩家:")
        playerlist_t = eval(playerkeep)
            
        if isinstance(playerlist_t,int):
            if playerlist_t in playerlist:
                winplayer = playerlist_t
                print("game over. The winner is "+str(winplayer))#若選擇繼續遊戲的玩家僅有一人,則遊戲結束進行結算
                return
                playerlist.clear()
            else:
                print("輸入有誤,請重新輸入")#若輸入玩家在本回閤中不存在則報錯並重新輸入

        elif isinstance(playerlist_t, tuple):
            playerlist_t = list(playerlist_t)
            for i in playerlist_t:
                if i not in playerlist:
                    tag = 1
            if tag == 1:
                print("輸入有誤,請重新輸入")#若輸入的玩家中有玩家在本回閤中不存在則報錯並重新輸入
            else:
                playerlist = playerlist_t
                pokerkeep = sample(Poker,1)#從剩餘卡牌中再抽取一張作為公共牌
                Publicpoker += pokerkeep
                pokerkeep = pokerkeep[0]
                print("公共牌: "+str(Publicpoker)+"   ")#將本回合的公共牌進行顯示

                for n in range(0,len(Poker)):#將所抽取的公共牌從剩餘卡牌中刪除
                    if Poker[n] == pokerkeep:
                        del Poker[n]                        
                        break
    for i in playerlist:
        Playerpoker.append(playerpoker[i-1])
    for ppoker in Playerpoker:
        finalresult.append(computeresult(ppoker, Publicpoker))#將每位玩家的手牌與公共牌代入計算最終結果
 
    finalscore = []
    finalscore_t = []
    finalplayer = []
    winner = []
    for t in range(0, len(finalresult)):
        finalscore.append(finalresult[t][0])
    
    maxscore = max(finalscore)#判斷此時所有玩家中最大的組合牌型別
    #若有多位玩家同時擁有最大型別的組合牌,則對他們最大的牌數位進行比較
    for t in range(0, len(finalresult)):
        if finalscore[t] == maxscore:
            finalplayer.append(t)    
    for t in finalplayer:
        finalscore_t.append(finalresult[t][1])
    maxscore_t = max(finalscore_t)    
    for t in finalplayer:
        if finalresult[t][1] == maxscore_t:
            winner.append(playerlist[t])
    ##輸出最終玩家
    print("game over.The winner is:")
    for t in winner:
        print("玩家:"+str(t))
    return 

gamestart函數唯一需要輸出的引數便是玩家的人數。在遊戲的開始,我們利用Pokerinitial函數獲得一副新卡牌,為每位玩家分發兩張手牌,並分發三張初始公共牌。當玩家人數在遊戲中途僅剩1時,我們認為遊戲已結束,並顯示最終贏家。若遊戲正常進行到最後(有兩位及以上玩家堅持到最後回合),則對每位玩家所擁有的最高等級卡牌組合進行計算與比較,得出最終贏家。若中途輸入繼續遊戲的玩家並不在當前玩家隊伍中時,系統會報錯並提示重新輸入。好了,話不多說,接下來我們便開始體驗遊戲吧!

遊戲體驗與展示

from Texas_Hold_em_Poker import gamestart

我們首先匯入我們所寫的德州撲克遊戲模組,並且僅需其中的gamstart函數。

n = input('請輸入要進行的遊戲的玩家人數:')
gamestart(int(n))

接著我們便通過編寫input函數從控制檯獲取進行遊戲的玩家人數。

我們將參與遊戲的玩家人數定為5

接著螢幕上便出現了每個玩家的手牌與公共牌。

接著我們輸入繼續遊戲的玩家

接著出現了下一回合的公共牌,我們接著讓1,2,3號玩家繼續遊戲

可以看到出現了最後回合的公共牌,並計算出了最終贏家。此時我們嘗試輸入上一回合併未繼續參與遊戲的玩家號,看看會出現什麼。

我們仍然將遊戲玩家人數定為5,並仍在第一回合讓1,2,3號玩家繼續遊戲

但我們在下一回合輸入已經退出遊戲的玩家4號與5號

可以看到系統報錯,並提示重新輸入,此時我們只需要輸入正確的玩家號碼便可以得到正確的結果。

模組不足與後續改進

在遊戲展示中我們可以看到玩家的手牌是公開的,而在實際中的德州撲克中,每位玩家的手牌都是完全保密的,這顯然不符合實際要求。但由於此程式碼僅能在控制檯中輸出顯示,所以也沒有很好的辦法對每位玩家的手牌進行保密,若接下來能實現視覺化便可通過設定金鑰的方式分別輸出每位玩家的手牌,實現很好的保密作用,或者在此基礎上將它發展成一個最終的小遊戲也是能實現保密性的。

除此以外在德州撲克中需要有不停的加註與跟注,這也可以寫成一個函數,這個等過段時間我稍微空了點可以補上去哈哈哈,有想法的朋友也可以自己來寫著試試。

到此這篇關於利用Python編寫簡易版德州撲克小遊戲的文章就介紹到這了,更多相關Python德州撲克內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com