2017-03-04 05:51:00 +03:00
|
|
|
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
|
2018-03-18 16:21:52 +03:00
|
|
|
for card in self.cards:
|
2017-03-04 05:51:00 +03:00
|
|
|
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."""
|
2018-03-07 03:37:46 +03:00
|
|
|
pass
|
2017-03-04 05:51:00 +03:00
|
|
|
|
|
|
|
|
|
|
|
class Deck(object):
|
|
|
|
|
|
|
|
def __init__(self, cards):
|
|
|
|
self.cards = cards
|
|
|
|
self.deal_index = 0
|
|
|
|
|
|
|
|
def remaining_cards(self):
|
2018-03-18 16:21:52 +03:00
|
|
|
return len(self.cards) - self.deal_index
|
2017-03-04 05:51:00 +03:00
|
|
|
|
2018-03-18 16:21:52 +03:00
|
|
|
def deal_card(self):
|
2017-03-04 05:51:00 +03:00
|
|
|
try:
|
|
|
|
card = self.cards[self.deal_index]
|
|
|
|
card.is_available = False
|
|
|
|
self.deal_index += 1
|
|
|
|
except IndexError:
|
|
|
|
return None
|
|
|
|
return card
|
|
|
|
|
2018-03-07 03:37:46 +03:00
|
|
|
def shuffle(self):
|
|
|
|
pass
|