21点扑克游戏

  • 案例目的

本案例通过一个21点扑克牌游戏的设计和实现,了解使用Python数据类型、控制流程和输入输出。

  • 案例内容

21点又名黑杰克(Blackjack),起源于法国,已流传到世界各地,有着悠久的历史。现在在世界各地的赌场中都可以看到二十一点,随着互联网的发展,二十一点开始走向网络时代。该游戏由2到6个人玩,使用除大小王之外的52张牌,游戏者的目标是使手中的牌的点数之和不超过21点且尽量大。

  • 实验环境

Pycharm、Anaconda

  • 案例研究

4.1 游戏规则

    开局时,庄家(dealer)给每个玩家(又称闲家)牌面向上发两张牌(明牌),再给庄家自己发两张牌,一张明牌,一张暗牌(牌面朝下)。

当所有的初始牌分发完毕后,如果玩家拿到的是A和T(无论顺序),就拥有黑杰克(Black Jack);若庄家的明牌为T,且暗牌为A,应直接翻开并拥有Black Jack;如果庄家的明牌为A,则玩家可以考虑买不买保险(Insurance),保险金额是赌注的一半且不退。此时,如果庄家的暗牌为10点牌(构成Black Jack),那么翻开此牌,购买保险的玩家得到1倍赌注;如果庄家没有Black Jack则保持暗牌,玩家继续游戏。若玩家为Black Jack且庄家为其他,玩家赢得1.5倍(或2倍,1赔2时)赌注;若庄家为Black Jack且玩家为其他,庄家赢得赌注;若庄家和玩家均为Black Jack,平局,玩家拿回自己的赌注。

接下来是正常的拿牌流程:首名非黑杰克玩家选择拿牌(Hit)、停牌(Stand)、加倍(Double)、分牌(Split,两牌相同时)或投降(Surrender,庄家赢得一半赌注);若选择拿牌,则后续只能选择拿牌或停牌。在发牌的过程中,如果玩家的牌点数的和超过21,玩家就输了——叫爆掉(Bust),庄家赢得赌注(无论庄家之后的点数是多少)。假如玩家没爆掉,又决定不再要牌了(停牌,或因加倍、投降而终止),则轮到下一名非黑杰克玩家选择。

当所有玩家停止拿牌后,庄家翻开暗牌,并持续拿牌直至点数不小于17(若有A,按最大而尽量不爆计算)。假如庄家爆掉了,那他就输了,玩家赢得1倍赌注;否则那么比点数大小,大为赢。点数相同为平局,玩家拿回自己的赌注。

4.2 设计思路

 

图 1  21点牌流程

4.3 设计代码

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(rank + ' ' + suit)  
    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, '1': 10, 'J': 10, 'Q': 10, 'K': 10, 'A': 11}  
    result = 0  # 初始化点数和为0  
    numAces = 0  # A的个数  
    # 计算点数和A的个数  
    for card in hand:  
        result += values[card[0]]  
        if card[0] == 'A':  
            numAces += 1  
    # 如果点数和>21,则尝试把A当做1来计算(即减去10),多个A循环减去10,直到点数<=21  
    while result > 21 and numAces > 0:  
        result -= 10  
        numAces -= 1  
    return result  
  
  
def blackjack():  
    """21点扑克牌游戏,计算机人工智能AI为庄家,用户为玩家"""  
    # 初始化一副洗好的扑克牌,初始化庄家和玩家手中的牌为空  
    deck = get_shuffled_deck()  
    house = []  # 庄家的牌  
    player = []  # 玩家的牌  
    # 依次给玩家和庄家各发两张牌  
    for i in range(2):  # 开始发两轮牌  
        deal_card(deck, player)  # 给玩家发一张牌  
        deal_card(deck, house)  # 给庄家发一张牌  
    # 打印一首牌  
    print('庄家的牌:', house)  
    print('玩家的牌:', player)  
  
    # 询问玩家是否继续拿牌,如果是,继续给玩家发牌  
    answer = input('是否继续拿牌(y/n,缺省为y): ')  
    while answer in ('', 'y', 'Y'):  
        card = deal_card(deck, player)  
        print('玩家拿到的牌为:{0}, {1}'.format(card, player))  
        # 计算牌点  
        if compute_total(player) > 21:  # 如果大于21点  
            print('爆掉 ... 玩家输牌!')  
            return  
        answer = input('是否继续拿牌(y/n,缺省为y): ')  # 继续询问是否拿牌  
  
    # 庄家(计算机人工智能)按“庄家规则”确定是否拿牌  
    while compute_total(house) < 17:  
        card = deal_card(deck, house)  
        print('庄家拿到的牌为:{0}, {1}'.format(card, house))  
        # 计算牌点  
        if compute_total(house) > 21:  # 如果大于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):  
        print('You loose.')  # house wins with a blackjack  
    elif playerTotal == 21 and 2 == len(player) < len(house):  
        print('庄家赢牌!')  # player wins with a blackjack  
    else:  
        print('平局!')  
  
  
if __name__ == '__main__':  
    blackjack()  

4.4 测试结果

图 2  21点牌多点测试结果 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈士奇谭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值