logo
OOD Interview Questions

设计 Deck of Cards

Deck of Cards 的面向对象设计示例

这份 notebook 由 Donne Martin 准备。Source 和 license info 在 GitHub

设计 Deck of Cards

Constraints & assumptions

  • 这是一个通用的 deck(用于 poker、blackjack 等)?
    • Yes,先设计 generic deck,再扩展到 blackjack
  • 可以假设 deck 有 52 张牌 + 4 suits?
    • Yes
  • 输入可以假设 valid 吗?
    • Assume they're valid

Solution

设计思路:

  • 先抽象出 CardDeck,保证适用于各种 card game
  • 再通过继承扩展 BlackJackCardBlackJackHand

核心对象

  • Suit:HEART / DIAMOND / CLUBS / SPADE
  • Card(abstract):value + suit + is_available
  • BlackJackCard:把 A、J/Q/K 规则封装到 value 计算
  • Hand:持牌集合,基础 score
  • BlackJackHand:处理 A 的多种计分方式
  • Deck:持有所有 cards,支持 shuffle / deal

Class 设计(示例)

class Suit(Enum):
    HEART = 0
    DIAMOND = 1
    CLUBS = 2
    SPADE = 3

class Card(metaclass=ABCMeta):
    def __init__(self, value, suit):
        self.value = value
        self.suit = suit
        self.is_available = True

class BlackJackCard(Card):
    def is_ace(self):
        return True if self._value == 1 else False

    def is_face_card(self):
        return True if 10 < self._value <= 13 else False

    @property
    def value(self):
        if self.is_ace():
            return 1
        elif self.is_face_card():
            return 10
        return self._value

class Hand(object):
    def __init__(self, cards):
        self.cards = cards

    def add_card(self, card):
        self.cards.append(card)

    def score(self):
        return sum(card.value for card in self.cards)

class BlackJackHand(Hand):
    BLACKJACK = 21

    def possible_scores(self):
        # 处理 A: 1 或 11
        pass

    def score(self):
        # 选 <= 21 的最大值,否则最小超出值
        pass

class Deck(object):
    def __init__(self, cards):
        self.cards = cards
        self.deal_index = 0

    def remaining_cards(self):
        return len(self.cards) - self.deal_index

    def deal_card(self):
        try:
            card = self.cards[self.deal_index]
            card.is_available = False
            self.deal_index += 1
            return card
        except IndexError:
            return None

    def shuffle(self):
        pass

Blackjack 的核心点

  • A 可以是 1 或 11,所以需要计算多个 possible scores
  • 结果选择规则:
    • 如果有 <= 21 的分数,取最大
    • 否则取最小超出值

可以扩展的点

  • Deck factory:根据 game 生成不同 deck(含 Jokers 等)
  • Shuffle 策略:Fisher–Yates
  • Multiple decks:casino blackjack 多副牌
  • Game engine:turn-based 状态机

参考与下载

Python 下载 Python 源码

相关练习题

设计 Deck of Cards

暂无相关练习题