Add Deck of Cards solution
This commit is contained in:
parent
98819e2a06
commit
0f517c709e
@ -0,0 +1,195 @@
|
|||||||
|
{
|
||||||
|
"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-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 True if self._value == 1 else False\n",
|
||||||
|
"\n",
|
||||||
|
" def is_face_card(self):\n",
|
||||||
|
" \"\"\"Jack = 11, Queen = 12, King = 13\"\"\"\n",
|
||||||
|
" return True if 10 < self._value <= 13 else False\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 card:\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
|
||||||
|
}
|
116
solutions/object_oriented_design/deck_of_cards/deck_of_cards.py
Normal file
116
solutions/object_oriented_design/deck_of_cards/deck_of_cards.py
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
from abc import ABCMeta, abstractmethod
|
||||||
|
from enum import Enum
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abstractmethod
|
||||||
|
def value(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@value.setter
|
||||||
|
@abstractmethod
|
||||||
|
def value(self, other):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BlackJackCard(Card):
|
||||||
|
|
||||||
|
def __init__(self, value, suit):
|
||||||
|
super(BlackJackCard, self).__init__(value, suit)
|
||||||
|
|
||||||
|
def is_ace(self):
|
||||||
|
return True if self._value == 1 else False
|
||||||
|
|
||||||
|
def is_face_card(self):
|
||||||
|
"""Jack = 11, Queen = 12, King = 13"""
|
||||||
|
return True if 10 < self._value <= 13 else False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def value(self):
|
||||||
|
if self.is_ace() == 1:
|
||||||
|
return 1
|
||||||
|
elif self.is_face_card():
|
||||||
|
return 10
|
||||||
|
else:
|
||||||
|
return self._value
|
||||||
|
|
||||||
|
@value.setter
|
||||||
|
def value(self, new_value):
|
||||||
|
if 1 <= new_value <= 13:
|
||||||
|
self._value = new_value
|
||||||
|
else:
|
||||||
|
raise ValueError('Invalid card value: {}'.format(new_value))
|
||||||
|
|
||||||
|
|
||||||
|
class Hand(object):
|
||||||
|
|
||||||
|
def __init__(self, cards):
|
||||||
|
self.cards = cards
|
||||||
|
|
||||||
|
def add_card(self, card):
|
||||||
|
self.cards.append(card)
|
||||||
|
|
||||||
|
def score(self):
|
||||||
|
total_value = 0
|
||||||
|
for card in card:
|
||||||
|
total_value += card.value
|
||||||
|
return total_value
|
||||||
|
|
||||||
|
|
||||||
|
class BlackJackHand(Hand):
|
||||||
|
|
||||||
|
BLACKJACK = 21
|
||||||
|
|
||||||
|
def __init__(self, cards):
|
||||||
|
super(BlackJackHand, self).__init__(cards)
|
||||||
|
|
||||||
|
def score(self):
|
||||||
|
min_over = sys.MAXSIZE
|
||||||
|
max_under = -sys.MAXSIZE
|
||||||
|
for score in self.possible_scores():
|
||||||
|
if self.BLACKJACK < score < min_over:
|
||||||
|
min_over = score
|
||||||
|
elif max_under < score <= self.BLACKJACK:
|
||||||
|
max_under = score
|
||||||
|
return max_under if max_under != -sys.MAXSIZE else min_over
|
||||||
|
|
||||||
|
def possible_scores(self):
|
||||||
|
"""Return a list of possible scores, taking Aces into account."""
|
||||||
|
# ...
|
||||||
|
|
||||||
|
|
||||||
|
class Deck(object):
|
||||||
|
|
||||||
|
def __init__(self, cards):
|
||||||
|
self.cards = cards
|
||||||
|
self.deal_index = 0
|
||||||
|
|
||||||
|
def remaining_cards(self):
|
||||||
|
return len(self.cards) - deal_index
|
||||||
|
|
||||||
|
def deal_card():
|
||||||
|
try:
|
||||||
|
card = self.cards[self.deal_index]
|
||||||
|
card.is_available = False
|
||||||
|
self.deal_index += 1
|
||||||
|
except IndexError:
|
||||||
|
return None
|
||||||
|
return card
|
||||||
|
|
||||||
|
def shuffle(self): # ...
|
Loading…
Reference in New Issue
Block a user