Python Projects|Poker (3) – 判斷撲克牌的牌型

by KC
0 comment

在這篇文章中,我們將學習如何使用 Python 來開發一個隨機產生 5張撲克牌後,可以進一步利用前面所學來進行牌型判斷。透過這個過程,讀者講可掌握 Python 程式設計的核心概念及許多基本用法,同時可以利用運算思維的方式來進行專案分析。讀著若是第一次接觸,也可以考慮參考前 2 篇文章 – 「Python Projects|Poker (1) – 隨機產生 1 張撲克牌」、「Python Projects|Poker (2) – 隨機產生 5 張不重複的撲克牌」。而這些專案都架構在 Python for Beginners 系列文章中,歡迎有興趣的讀者參考。

1. 學習目標

  1. 理解並使用 Python 的 random 模組來產生隨機數據。
  2. 學習如何操作和處理串列(List)數據。
  3. 理解和應用複雜的資料結構,如字典(Dictionary)和集合(Set)。
  4. 學習使用函數和控制結構(迴圈和條件式)來執行複雜邏輯判斷。
  5. 學習如何根據規則判斷撲克牌的牌型。

2. 運算思維

  1. 分解:將牌型判斷問題分解為識別不同牌型的多個子問題。
  2. 抽象:將撲克牌的牌型判斷過程抽象化,不考慮具體牌的細節定義函式,建立和使用函式(如generate_poker_hands()evaluate_hands())來抽象化牌的生成和牌型的判斷過程。。
  3. 模式識別:識別牌型判斷中的共通模式,如計算相同數字的牌的數量。識別牌型的共同特徵,並思考如何根據數字和花色的出現次數來識別牌型。。
  4. 演算法設計:設計一個系統化的過程來判斷撲克牌的牌型。

3. 步驟說明

Step 1. 導入 random 模組

首先,我們需要使用 Python 的 random 模組來實現隨機性,這是生成隨機撲克牌的關鍵。

import random

Step 2. 定義撲克牌花色和數字

定義兩個串列(List):suitsnums,它們分別代表撲克牌的四種花色(♠, ♥, ♦, ♣)和十三種數字(A、2 到 K)。

suits = ['♠', '♥', '♦', '♣']  # 花色
nums = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']  # 數字

Step 3. 建立「產生撲克牌函式」(5張)

  • 我們需要一個函式 generate_poker_hands 來產生五張不重複的撲克牌。
  • 在這個函式中,使用一個 while 迴圈持續產生撲克牌,直到我們得到五張不同的牌為止。
  • 迴圈中使用 random.choice() 隨機選取花色和數字,組成一張牌。
  • 檢查這張牌是否已在串列中,以避免重複,並確保最終得到 5 張不重複的牌。
def generate_poker_hands():
    cards = []
    while len(cards) < 5:
        my_suit = random.choice(suits)  # 隨機選擇花色
        my_num = random.choice(nums)    # 隨機選擇數字
        card = my_suit + my_num         # 組合成一張牌
        if card not in cards:           # 檢查是否重複
            cards.append(card)          # 添加到牌組中
    return cards

Step 4. 建立「判斷撲克牌牌型函式」

  • card_suits 儲存了傳入牌的花色card_nums 則儲存了數字
  • 數字進行排序,以便於判斷順子(Straight)。
  • 使用 num_counts 字典來計算每個數字出現的次數,這對於判斷對子、三條、四條等牌型非常重要。
  • 判斷同花(Flush):如果花色集合的長度為 1,則所有牌花色相同。
  • 判斷順子(Straight):首先檢查是否有 5 個不同的數字(排除對子、三條等情況)。然後,檢查數字是否連續。對於特殊情況(A可以作為最高牌和最低牌),如{'A', '2', '3', '4', '5'}也被視為順子。
  • 先檢查是否為同花順(Straight flush):同時滿足同花和順子的條件。
  • 檢查其他牌型:四條(Four of a kind)、葫蘆(Full house)、同花(Flush)、順子(Straight)、三條(Three of a kind)、兩對(Two pair)、一對(One pair),以及散牌(High card)。

整理上述內容後,將牌型判斷的關鍵邏輯摘要如下:

  • 順子(Straight):透過檢查排序後的數字是否連續來判斷。對於 A 的特殊處理(既可以作為最高牌也可以作為最低牌),增加了一個特定條件來判斷 A5 的順子。
  • 同花(Flush):檢查所有牌的花色是否相同。
  • 同花順(Straight flush):同時滿足同花和順子的條件。
  • 四條、三條、對子:根據數字的出現次數來判斷。例如,四條表示有一個數字出現了四次。

其函式定義可參考如下:

def classify_hand(cards):
    card_suits = [card[0] for card in cards]
    card_nums = [card[1:] for card in cards]

    # 數字排序
    card_nums_sorted = sorted(card_nums, key=lambda x: nums.index(x))
    num_counts = {num: card_nums.count(num) for num in set(card_nums)}

    is_flush = len(set(card_suits)) == 1
    is_straight = False

    if len(set(card_nums_sorted)) == 5:
        indices = [nums.index(num) for num in card_nums_sorted]
        if max(indices) - min(indices) == 4:
            is_straight = True
        elif set(card_nums_sorted) == {'A', '2', '3', '4', '5'}:
            is_straight = True

    if is_flush and is_straight:
        return '同花順(Straight flush)'
    elif 4 in num_counts.values():
        return '鐵支(Four of a kind)'
    elif 3 in num_counts.values() and 2 in num_counts.values():
        return '葫蘆(Full house)'
    elif is_flush:
        return '同花(Flush)'
    elif is_straight:
        return '順子(Straight)'
    elif 3 in num_counts.values():
        return '三條(Three of a kind)'
    elif list(num_counts.values()).count(2) == 2:
        return '兩對(Two pair)'
    elif 2 in num_counts.values():
        return '一對(One pair)'
    return '散牌(High card)'

Step 5. 呼叫「產生撲克牌函式」

呼叫前面定義的產生撲克牌函式 generate_poker_hands() 來隨機產生五張撲克牌。

cards = generate_poker_hands()

Step 6. 呼叫「判斷撲克牌牌型函式」

呼叫判斷撲克牌牌型函式 classify_hand(cards) 來判斷牌型。

hand_type = classify_hand(cards)

Step 7. 列印撲克牌牌型

列印出隨機產生的 5 張撲克牌及其牌型。

print(f"隨機5張撲克牌是:{cards}") 
print(f"牌型為:{hand_type}") 

Step 8. 整合所有步驟及程式碼

將上述步驟程式碼整合後,並且試著執行數次,看看是否符合專案目標。你將完成隨機產生 5 張撲克牌及判斷型的專案。

# 導入 random 模組
import random

# 定義撲克牌花色和數字
suits = ['♠', '♥', '♦', '♣']  # 花色
nums = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']  # 數字

# 建立「產生撲克牌函式」(5張)
def generate_poker_hands():
    cards = []
    while len(cards) < 5:
        my_suit = random.choice(suits)  # 隨機選擇花色
        my_num = random.choice(nums)    # 隨機選擇數字
        card = my_suit + my_num         # 組合成一張牌
        if card not in cards:           # 檢查是否重複
            cards.append(card)          # 添加到牌組中
    return cards

# 建立「判斷撲克牌牌型函式」
def classify_hand(cards):
    card_suits = [card[0] for card in cards]
    card_nums = [card[1:] for card in cards]

    # 數字排序
    card_nums_sorted = sorted(card_nums, key=lambda x: nums.index(x))
    num_counts = {num: card_nums.count(num) for num in set(card_nums)}

    is_flush = len(set(card_suits)) == 1
    is_straight = False

    if len(set(card_nums_sorted)) == 5:
        indices = [nums.index(num) for num in card_nums_sorted]
        if max(indices) - min(indices) == 4:
            is_straight = True
        elif set(card_nums_sorted) == {'A', '2', '3', '4', '5'}:
            is_straight = True

    if is_flush and is_straight:
        return '同花順(Straight flush)'
    elif 4 in num_counts.values():
        return '鐵支(Four of a kind)'
    elif 3 in num_counts.values() and 2 in num_counts.values():
        return '葫蘆(Full house)'
    elif is_flush:
        return '同花(Flush)'
    elif is_straight:
        return '順子(Straight)'
    elif 3 in num_counts.values():
        return '三條(Three of a kind)'
    elif list(num_counts.values()).count(2) == 2:
        return '兩對(Two pair)'
    elif 2 in num_counts.values():
        return '一對(One pair)'
    return '散牌(High card)'

# 呼叫「產生撲克牌函式」
cards = generate_poker_hands()      # 生成5張隨機撲克牌

# 呼叫「判斷撲克牌牌型函式」
hand_type = classify_hand(cards)    # 判斷牌型

# 列印撲克牌及牌型
print(f"隨機5張撲克牌是:{cards}")   # 列印產生的撲克牌
print(f"牌型為:{hand_type}")        # 列印判斷後的牌型

執行結果:

隨機5張撲克牌是:['♠8', '♦A', '♥A', '♠2', '♥5']
牌型為:一對(One pair)
隨機5張撲克牌是:['♠7', '♦7', '♣4', '♦9', '♥7']
牌型為:三條(Three of a kind)

4. 心得與結論

透過這個小專案,初學者將可學習如何使用 Python 來實作撲克牌的基本操作,從產生隨機撲克牌到判斷牌型。這不僅加深了讀者對 Python 編程的理解,也提升了解決實際問題的能力。透過實踐,我們能夠更好地掌握程式設計的邏輯和技巧,為更複雜的專案奠定基礎。

同時筆者以 Python for Beginners 系列文章為學基礎,先設計了 3 個簡單有趣,且循序漸進地的 Poker 專案,分別是「Python Projects|Poker (1) – 隨機產生 1 張撲克牌」、「Python Projects|Poker (2) – 隨機產生 5 張不重複的撲克牌」、以及本篇「Python Projects|Poker (3) – 判斷撲克牌的牌型」,可讓初學者以非常輕鬆有趣的方式融會貫通 Python 的程式設計。後續也會以此為基礎,持續發表相關專案給讀者。

讀者若想要多了解 Python 的一些基礎知識,可以參考 Python for Beginners 系列文章,當中完整介紹 Python 基礎知識,並運用大量範例及 Quiz 來協助讀者學習。如果讀者也想知道其他重要的科技知識,例如人工智慧、機器學習、深度學習及神經網路相關基礎知識,則可以參考這一本書【從 AI 到 生成式 AI:40 個零程式的實作體驗,培養新世代人工智慧素養】,它將帶領讀者不會程式、不會數學也OK!的情況下,建立最完整的 AI 入門知識。

如果你喜歡這篇文章歡迎訂閱、分享(請載名出處)追蹤,並持續關注最新文章。同時 FB 及 IG 也會不定期提供國內外教育與科技新知。

Related Posts

Leave a Comment

error: Content is protected !!