Python實現21點撲克牌遊戲


莊家的牌:♣ 10  ♦ Q  
玩家的牌:♦ 4  ♥ 8  
是否繼續拿牌(y/n,缺省爲y):y
玩家拿到的牌爲:♦ 4  ♥ 8  ♥ K  
爆掉  玩家輸牌!

21點撲克牌遊戲概述

21點又名黑傑克(Blackjack) ,是一種流行的撲克遊戲。該遊戲由兩到六個人玩,使用除大小王之外的52張牌,遊戲者的目標是使手中的牌的點數之和不超過21點且儘量大。

一手撲克牌的點數的計算規則如下:

  • 2至9牌,按其原點數計算;
  • 10、J、Q、K牌都算作10點(一般記作T,即Ten) ;
  • A牌(Ace)既可以算作1點也可以算作11點,由玩家自己決定
  • (當玩家停牌時,點數一律視爲最大而儘量不爆,如A+K爲21,A+5+8爲14而不是24)。

21點撲克牌遊戲設計思路

按下列規則模擬21點撲克牌遊戲:

  1. 計算機人工智能AI作爲莊家(House),用戶作爲玩家(Player) 。
  2. 遊戲開始時, 莊家從洗好的一副牌中發牌:第1張牌發給玩家, 第2張牌發給莊家,第3張牌發給玩家,第4張牌發給莊家。
  3. 然後,詢問玩家是否需要繼續“拿牌”,通過一次或多次“拿牌”,玩家嘗試使手中撲克牌的點數和接近21。如果玩家手中撲克牌的點數之和超過21,則玩家輸牌。
  4. 當玩家決定 “停牌”(即,不再“拿牌”),則輪到莊家使用下列規則(“莊家規則”)“拿牌”:如果莊家手中的最佳點數之和小於17,則必須“拿牌”:,如果點數之和大於或等於17,則“停牌”。如果莊家的點數之和超過21,則玩家獲勝。
  5. 最後, 比較玩家和莊家的點數。如果玩家的點數大,則獲勝。如果玩家的點數小,則輸牌。如果點數相同,則平局。但玩家和莊家的牌值都是21點,此時擁有blackjack (一張Ace 和一張點數爲10的牌)方獲勝。

程序的流程如下:

  • 初始化一 副洗好的撲克牌,初始化莊家和玩家手中的牌爲空
    調用函數get_shuffled_deck()
def get_shuffled_deck():
    """初始化包括52張撲克牌的列表,並混排後返回,表示一副洗好的撲克牌"""
    # 花色suits和序號
    suits = {'♣', '♠', '♦', '♥'}
    ranks = {'2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'}
    deck = []
    # 創建一副52張的撲克牌
    for suit in suits:
        for rank in ranks:
            deck.append(suit + ' ' + rank)
    random.shuffle(deck)
    return deck
  • 依次給玩家和莊家各發兩張牌
    調用函數deal_card()
def deal_card(deck, participant):
    """發一張牌給參與者participant"""
    card = deck.pop()
    participant.append(card)
    return card
  • 玩家拿牌: 詢問玩家是否繼續拿牌,如果是,繼續給玩家發牌(調用函數deal_ card()) ,並計算玩家牌點compute_total(),如果大於21點,輸出“玩家輸牌!”信息,並返回。
def compute_total(hand):
    """計算並返回一手牌的點數和"""
    values = {'2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, \
              '9':9, '10':10, 'J':10, 'Q':10, 'K':10, ' A':11}
    result = 0 #初始化點數和爲0
    numAces = 0 #A的個數

    # 計算點數和A的個數
    for card in hand:
        result += values[card[2:]]
        if card[2] == 'A':
            numAces += 1
    
    #如果點數和>21,則嘗試把A當做1來計算
    # (即減去10),多個A循環減去10,直到點數<=21
    while result > 21 and numAces > 0:
        result -= 10
        numAces -= 1
    return result
  • 莊家拿牌:莊家(計算機人工智能AI)按“莊家規則”確定是否拿牌,如果是,繼續給莊家發牌(調用函數deal_card()) ,並計算莊家牌點compute_total(),如果大於21點,輸出“玩家贏牌!”信息,並返回。

  • 分別計算莊家和玩家的點數,比較點數大小,輸出輸贏結果信息。

語義化:

  • shuffled deck,洗牌臺
  • deal,發牌

random模塊的函數使用

  • random.shuffle(lst) 將序列的所有元素隨機排序。
    參數:lst 列表

列表的函數使用

  • s.append(x) 把對象x追加到列表s的尾部
  • s.pop(i) 彈出下標i處元素,當省略i時彈出列表的最後一個元素

21點撲克牌遊戲實現

import random

def get_shuffled_deck():
    """初始化包括52張撲克牌的列表,並混排後返回,表示一副洗好的撲克牌"""
    # 花色suits和序號
    suits = {'♣', '♠', '♦', '♥'}
    ranks = {'2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'}
    deck = []
    # 創建一副52張的撲克牌
    for suit in suits:
        for rank in ranks:
            deck.append(suit + ' ' + rank)
    random.shuffle(deck)
    return deck

def deal_card(deck, participant):
    """發一張牌給參與者participant"""
    card = deck.pop()
    participant.append(card)
    return card

def compute_total(hand):
    """計算並返回一手牌的點數和"""
    values = {'2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, \
              '9':9, '10':10, 'J':10, 'Q':10, 'K':10, ' A':11}
    result = 0 #初始化點數和爲0
    numAces = 0 #A的個數

    # 計算點數和A的個數
    for card in hand:
        result += values[card[2:]]
        if card[2] == 'A':
            numAces += 1
    
    #如果點數和>21,則嘗試把A當做1來計算
    # (即減去10),多個A循環減去10,直到點數<=21
    while result > 21 and numAces > 0:
        result -= 10
        numAces -= 1
    return result

def print_hand(hand):
    for card in hand:
        print(card, end = '  ')
    print()

def blackjack():
    """21點撲克牌遊戲,計算機人工智能AI爲莊家,用戶爲玩家"""
    # 初始化一副洗好的撲克牌,初始化莊家和玩家手中的牌爲空
    deck = get_shuffled_deck()
    house = [] # 莊家的牌
    player = [] # 玩家的牌
    
    # 依次給玩家和莊家各發兩張牌
    for i in range(2):
        deal_card(deck, player)
        deal_card(deck, house)
        
    # 打印一手牌
    print('莊家的牌:', end = ''); print_hand(house)
    print('玩家的牌:', end = ''); print_hand(player)

    # 詢問玩家是否繼續拿牌,如果是,繼續給玩家發牌
    answer = input('是否繼續拿牌(y/n,缺省爲y):')
    while answer in ('', 'y', 'Y'):
        card = deal_card(deck, player)
        print('玩家拿到的牌爲:', end = ''); print_hand(player)
        # 計算牌點
        if compute_total(player) > 21:
            print('爆掉  玩家輸牌!')
            return
        answer = input('是否繼續拿牌(y/n,缺省爲y):')

    # 莊家(計算機人工智能)按“莊家規則”確定是否拿牌
    while compute_total(house) < 17:
        card = deal_card(deck, house)
        print('莊家拿到的牌爲:', end =''); print_hand(house)
        # 計算牌點
        if compute_total(house) > 21:
            print('爆掉  玩家贏牌!')
            return

    # 分別計算莊家和玩家的點數,比較點數大小,輸出輸贏結果信息
    houseTotal, playerTotal = compute_total(house), compute_total(player)
    if houseTotal > playerTotal:
        print('莊家贏牌!')
    elif houseTotal < playerTotal:
        print('玩家贏牌!')
    elif houseTotal == 21 and 2 == len(house) < len(player) : # 擁有blackjack的莊家贏牌
        print('莊家贏牌!')
    elif playerTotal == 21 and 2 == len(player) < len(house) : # 擁有blackjack的玩家贏牌
        print('玩家贏牌!')
    else:
        print('平局!')

if __name__ == '__main__':
    blackjack()

運行結果示例一:

莊家的牌:♣ 10  ♦ Q  
玩家的牌:♦ 4  ♥ 8  
是否繼續拿牌(y/n,缺省爲y):y
玩家拿到的牌爲:♦ 4  ♥ 8  ♥ K  
爆掉  玩家輸牌!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章