{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/system-design-primer)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Design a deck of cards" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Constraints and assumptions\n", "\n", "* Is this a generic deck of cards for games like poker and black jack?\n", " * Yes, design a generic deck then extend it to black jack\n", "* Can we assume the deck has 52 cards (2-10, Jack, Queen, King, Ace) and 4 suits?\n", " * Yes\n", "* Can we assume inputs are valid or do we have to validate them?\n", " * Assume they're valid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Solution" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Overwriting deck_of_cards.py\n" ] } ], "source": [ "%%writefile deck_of_cards.py\n", "from abc import ABCMeta, abstractmethod\n", "from enum import Enum\n", "import sys\n", "\n", "\n", "class Suit(Enum):\n", "\n", " HEART = 0\n", " DIAMOND = 1\n", " CLUBS = 2\n", " SPADE = 3\n", "\n", "\n", "class Card(metaclass=ABCMeta):\n", "\n", " def __init__(self, value, suit):\n", " self.value = value\n", " self.suit = suit\n", " self.is_available = True\n", "\n", " @property\n", " @abstractmethod\n", " def value(self):\n", " pass\n", "\n", " @value.setter\n", " @abstractmethod\n", " def value(self, other):\n", " pass\n", "\n", "\n", "class BlackJackCard(Card):\n", "\n", " def __init__(self, value, suit):\n", " super(BlackJackCard, self).__init__(value, suit)\n", "\n", " def is_ace(self):\n", " return self._value == 1\n", "\n", " def is_face_card(self):\n", " \"\"\"Jack = 11, Queen = 12, King = 13\"\"\"\n", " return 10 < self._value <= 13\n", "\n", " @property\n", " def value(self):\n", " if self.is_ace() == 1:\n", " return 1\n", " elif self.is_face_card():\n", " return 10\n", " else:\n", " return self._value\n", "\n", " @value.setter\n", " def value(self, new_value):\n", " if 1 <= new_value <= 13:\n", " self._value = new_value\n", " else:\n", " raise ValueError('Invalid card value: {}'.format(new_value))\n", "\n", "\n", "class Hand(object):\n", "\n", " def __init__(self, cards):\n", " self.cards = cards\n", "\n", " def add_card(self, card):\n", " self.cards.append(card)\n", "\n", " def score(self):\n", " total_value = 0\n", " for card in self.cards:\n", " total_value += card.value\n", " return total_value\n", "\n", "\n", "class BlackJackHand(Hand):\n", "\n", " BLACKJACK = 21\n", "\n", " def __init__(self, cards):\n", " super(BlackJackHand, self).__init__(cards)\n", "\n", " def score(self):\n", " min_over = sys.MAXSIZE\n", " max_under = -sys.MAXSIZE\n", " for score in self.possible_scores():\n", " if self.BLACKJACK < score < min_over:\n", " min_over = score\n", " elif max_under < score <= self.BLACKJACK:\n", " max_under = score\n", " return max_under if max_under != -sys.MAXSIZE else min_over\n", "\n", " def possible_scores(self):\n", " \"\"\"Return a list of possible scores, taking Aces into account.\"\"\"\n", " # ...\n", "\n", "\n", "class Deck(object):\n", "\n", " def __init__(self, cards):\n", " self.cards = cards\n", " self.deal_index = 0\n", "\n", " def remaining_cards(self):\n", " return len(self.cards) - deal_index\n", "\n", " def deal_card():\n", " try:\n", " card = self.cards[self.deal_index]\n", " card.is_available = False\n", " self.deal_index += 1\n", " except IndexError:\n", " return None\n", " return card\n", "\n", " def shuffle(self): # ..." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.4.3" } }, "nbformat": 4, "nbformat_minor": 0 }