Python面向对象实战之扑克游戏

一、Python面向对象实战之扑克游戏

我们的扑克只有52张牌(没有大小王),游戏需要将 52 张牌发到 4 个玩家的手上,

每个玩家手上有 13 张牌,按照黑桃、红心、草花、方块的顺序和点数从小到大排列,

以下实现:21点游戏(Black Jack)。

python 复制代码
import random
from enum import Enum


class Suite(Enum):
    """花色(枚举)"""
    SPADE, HEART, CLUB, DIAMOND = range(4)


class Card:
    """牌"""

    def __init__(self, suite, face):
        self.suite = suite
        self.face = face

    def __repr__(self):
        suites = '♠♥♣♦'
        faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
        return f'{suites[self.suite.value]}{faces[self.face]}'  # 返回牌的花色和点数

    def __lt__(self, other):
        if self.suite == other.suite:
            return self.face < other.face  # 花色相同比较点数的大小
        return self.suite.value < other.suite.value  # 花色不同比较花色对应的值


class Poker:
    """扑克"""

    def __init__(self):
        self.cards = [Card(suite, face)
                      for suite in Suite
                      for face in range(1, 14)]  # 52张牌构成的列表
        self.current = 0  # 记录发牌位置的属性

    def shuffle(self):
        """洗牌"""
        self.current = 0
        random.shuffle(self.cards)  # 通过random模块的shuffle函数实现随机乱序

    def deal(self):
        """发牌"""
        card = self.cards[self.current]
        self.current += 1
        return card

    @property
    def has_next(self):
        """还有没有牌可以发"""
        return self.current < len(self.cards)


class Player:
    """玩家"""

    def __init__(self, name):
        self.name = name
        self.cards = []  # 玩家手上的牌

    def get_one(self, card):
        """摸牌"""
        self.cards.append(card)

    def arrange(self):
        """整理手上的牌"""
        self.cards.sort()

    def calculate_score(self):
        """计算手牌点数(A可计为1或11,J/Q/K计为10)"""
        score = 0
        aces = 0  # 记录A的数量
        for card in self.cards:
            if card.suite == 1:  # A
                score += 11
                aces += 1
            elif 2 <= card.face <= 10:  # 2-10
                score += card.face
            else:  # J/Q/K
                score += 10
        # 如果总分超过21分,且手上有A,将A视为1分
        while score > 21 and aces > 0:
            score -= 10
            aces -= 1
        return score


class BlackJack:
    """21点"""

    def __init__(self):
        self.poker = Poker()
        self.player = Player('玩家')
        self.dealer = Player('庄家')

    def start_game(self):
        """开始游戏"""
        print("===== 21点游戏开始 =====")
        self.poker.shuffle()
        # 初始发牌,每人两张
        for _ in range(2):
            self.player.get_one(self.poker.deal())
            self.dealer.get_one(self.poker.deal())
        # 显示初始牌面
        self.show_hands(show_dealer_first_card=False)
        # 玩家回合
        self.player_turn()
        # 庄家回合(如果玩家未爆牌)
        if self.player.calculate_score() <= 21:
            self.dealer_turn()
        # 结算
        self.settle()

    def player_turn(self):
        """玩家回合"""
        while True:
            choice = input('要牌(Hit)或停牌(Stand)?[H/S]').strip().upper()
            if choice == 'H':
                self.player.get_one(self.poker.deal())
                self.show_hands(show_dealer_first_card=False)
                if self.player.calculate_score() > 21:
                    print('爆牌!你的点数超过21!')
                    break
            elif choice == 'S':
                break
            else:
                print('输错了,傻屌!')

    def dealer_turn(self):
        """庄家回合(规则:点数<17必须要牌)"""
        print("\n庄家回合。。。")
        self.show_hands(show_dealer_first_card=True)
        while self.dealer.calculate_score() < 17:
            self.dealer.get_one(self.poker.deal())
            print(f'庄家要牌:{self.dealer.cards[-1]}')
            if self.dealer.calculate_score() > 21:
                print('庄家爆牌!')
                break

    def show_hands(self, show_dealer_first_card=False):
        """显示当前手牌"""
        print("\n=== 当前牌面 ===")
        print(f"玩家手牌:{self.player.cards} 点数:{self.player.calculate_score()}")
        if show_dealer_first_card:
            print(f'庄家手牌:{self.dealer.cards} 点数:{self.dealer.calculate_score()}')
        else:
            # 隐藏庄家第二张牌
            print(f'庄家手牌:[{self.dealer.cards[0]},?]')

    def settle(self):
        """结算"""
        player_score = self.player.calculate_score()
        dealer_score = self.dealer.calculate_score()

        print('\n=== 游戏结果 ===')
        print(f'玩家点数:{player_score}')
        print(f'庄家点数:{dealer_score}')

        if player_score > 21:
            print('你爆牌了,庄家赢!')
        elif dealer_score > 21:
            print('庄家爆牌,你赢!')
        elif player_score > dealer_score:
            print('你赢!')
        elif player_score < dealer_score:
            print('庄家赢!')
        else:
            print('平了!')
if __name__ == '__main__':
    game = BlackJack()
    game.start_game()
  • ===== 21点游戏开始 =====

  • === 当前牌面 ===

  • 玩家手牌:[♠Q, ♠4] 点数:14

  • 庄家手牌:[♥6,?]

  • 要牌(Hit)或停牌(Stand)?[H/S]h

  • === 当前牌面 ===

  • 玩家手牌:[♠Q, ♠4, ♦J] 点数:24

  • 庄家手牌:[♥6,?]

  • 爆牌!你的点数超过21!

  • === 游戏结果 ===

  • 玩家点数:24

  • 庄家点数:14

  • 你爆牌了,庄家赢!