Implement playing cards
This commit is contained in:
parent
857b26f4a3
commit
74bd1c4415
316
blackjack.py
316
blackjack.py
|
@ -4,6 +4,12 @@ import random
|
|||
class NoMoreCards(Exception):
|
||||
pass
|
||||
|
||||
class InvalidCard(Exception):
|
||||
pass
|
||||
|
||||
class InvalidSuit(Exception):
|
||||
pass
|
||||
|
||||
class Game(object):
|
||||
def __init__(self, deck, rules):
|
||||
self.players = []
|
||||
|
@ -13,50 +19,86 @@ class Game(object):
|
|||
|
||||
# Which index player's turn is it?
|
||||
self.player_index = 0
|
||||
print("Created game.")
|
||||
self.last_player = None
|
||||
|
||||
@property
|
||||
def current_player(self):
|
||||
return self.players[self.player_index]
|
||||
|
||||
def next_turn(self):
|
||||
current_player = self.players[self.current_player]
|
||||
current_player = self.players[self.player_index]
|
||||
print(f"Current player is {current_player}")
|
||||
if self.player_index == len(self.players):
|
||||
print(f"Reached the end of players: {self.players}, {self.current_player}")
|
||||
print(f"Reached the end of players: {self.players}, {current_player}")
|
||||
self.current_player = 0
|
||||
else:
|
||||
self.current_player += 1
|
||||
print(f"Incrementing current_player: {self.players}, {self.current_player}")
|
||||
print(f"Incrementing current_player: {self.players}, {current_player}")
|
||||
|
||||
def determine_start(self, first_card):
|
||||
"""Determine who starts the game."""
|
||||
card_map = {}
|
||||
for player in self.players:
|
||||
player_min = player.hand.min_of_suit_or_none(first_card.suit)
|
||||
if player_min is None:
|
||||
card_map[None] = player
|
||||
else:
|
||||
card_map[str(player_min)] = player
|
||||
if len(card_map) == 1 and None in card_map:
|
||||
return card_map[None]
|
||||
else:
|
||||
without_none = {k:v for k,v in card_map.items() if k}
|
||||
min_card = min(without_none.keys())
|
||||
min_player = without_none[min_card]
|
||||
return min_player
|
||||
|
||||
def add_players(self, *players):
|
||||
for player in players:
|
||||
print(f"Adding player: {player}")
|
||||
self.players.append(player)
|
||||
|
||||
def flipcard(self):
|
||||
if not len(self.playdeck.cards) == 0:
|
||||
return False
|
||||
first_card = self.drawdeck.draw()
|
||||
print(f"First card is: {first_card}")
|
||||
self.playdeck.put(first_card)
|
||||
starter = self.determine_start(first_card)
|
||||
print(f"{starter} to start!")
|
||||
|
||||
def deal(self):
|
||||
for player in self.players:
|
||||
num_cards = self.rules.initial_cards
|
||||
cards = list(self.drawdeck.draw_num(num_cards))
|
||||
print("Cards", cards)
|
||||
player.deck.put_cards(*cards)
|
||||
player.hand.put_cards(*cards)
|
||||
if self.rules.flipcard:
|
||||
first_card = self.drawdeck.draw()
|
||||
print(f"First card is: {first_card}")
|
||||
self.playdeck.put(first_card)
|
||||
self.flipcard()
|
||||
|
||||
def play_card(self, player, card):
|
||||
def play_card(self, player, card, special=True):
|
||||
print(f"Player {player} attempting to play {card}")
|
||||
last_card = self.playdeck.last_card
|
||||
print(f"Last card {last_card}")
|
||||
is_playable = self.rules.is_playable_on(last_card, card)
|
||||
if player == self.last_player:
|
||||
special = False
|
||||
is_playable = self.rules.is_playable_on(last_card, card, special=special)
|
||||
print("Card is playable", is_playable)
|
||||
#current_card = self.d
|
||||
if is_playable:
|
||||
actual_card = player.hand.draw_card(card)
|
||||
self.playdeck.put(actual_card)
|
||||
self.last_player = player
|
||||
return is_playable
|
||||
|
||||
#def play_combination(self, player, *cards):
|
||||
# print(f"Player {player} attempting to play combination {cards}")
|
||||
|
||||
|
||||
class Player(object):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.deck = Hand()
|
||||
print(f"Created player {name}")
|
||||
self.hand = Hand()
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
return f"@{self.name}"
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
@ -66,11 +108,9 @@ class SetOfCards(object):
|
|||
self.cards = []
|
||||
if cards:
|
||||
self.cards = [*cards]
|
||||
print(f"Created deck with cards: {self.cards}")
|
||||
|
||||
def draw(self):
|
||||
card = self.cards.pop()
|
||||
print(f"Drawing {card} from deck")
|
||||
return card
|
||||
|
||||
def draw_num(self, num):
|
||||
|
@ -78,17 +118,28 @@ class SetOfCards(object):
|
|||
yield self.cards.pop()
|
||||
|
||||
def put(self, card):
|
||||
print("Putting card on deck:", card)
|
||||
self.cards.append(card)
|
||||
|
||||
def put_cards(self, *cards):
|
||||
for card in cards:
|
||||
self.put(card)
|
||||
|
||||
def draw_card(self, card):
|
||||
for mycard in self.cards:
|
||||
if card == mycard:
|
||||
self.cards.remove(mycard)
|
||||
print(f"Returned {mycard} and amended cards: {self.cards}")
|
||||
return mycard
|
||||
|
||||
def __str__(self):
|
||||
return str(self.cards)
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
class Deck(SetOfCards):
|
||||
def shuffle(self):
|
||||
random.shuffle(self.cards)
|
||||
print(f"Shuffled deck: {self.cards}")
|
||||
|
||||
@property
|
||||
def last_card(self):
|
||||
|
@ -97,44 +148,70 @@ class Deck(SetOfCards):
|
|||
else:
|
||||
raise NoMoreCards
|
||||
|
||||
@property
|
||||
def last_cards(self):
|
||||
if self.cards:
|
||||
return self.cards[:5]
|
||||
|
||||
def fill(self):
|
||||
for suit_str in "SHCD":
|
||||
values_str_10 = [str(x) for x in range(2, 11)]
|
||||
for val_str in [*values_str_10, "J", "Q", "K", "A"]:
|
||||
card_str = f"{suit_str}{val_str}"
|
||||
print("card_str", card_str)
|
||||
card = Card(card_str)
|
||||
self.cards.append(card)
|
||||
print("cards after fill", self.cards)
|
||||
print("len after fill", len(self.cards))
|
||||
|
||||
class Hand(SetOfCards):
|
||||
pass
|
||||
def have_suit(self, suit):
|
||||
"""Have we got this suit?"""
|
||||
for card in self.cards:
|
||||
if card.suit == suit:
|
||||
return True
|
||||
return False
|
||||
|
||||
def min_of_suit_or_none(self, suit):
|
||||
if not self.have_suit(suit):
|
||||
return None
|
||||
suit_cards = []
|
||||
for card in self.cards:
|
||||
if card.suit == suit:
|
||||
suit_cards.append(card)
|
||||
return min(suit_cards)
|
||||
|
||||
class Rules(object):
|
||||
def __init__(self):
|
||||
self.initial_cards = 2 # Number of cards to start with
|
||||
self.initial_cards = 7 # Number of cards to start with
|
||||
self.flipcard = True # Initially flip a card
|
||||
self.jacks_on_twos = False # Can we play Jacks on 2s?
|
||||
self.jacks_on_eights = False # Can we play Jacks on 8s?
|
||||
|
||||
self.set_power_cards()
|
||||
|
||||
print("Created rules.")
|
||||
|
||||
def set_power_cards(self):
|
||||
# Next player has to pick up two cards if they don't have a
|
||||
# card of the same value
|
||||
self.pick_up_two = Value(2)
|
||||
self.pick_up_two = Value("2")
|
||||
# Next player has to skip a go if they don't have another
|
||||
self.skip_a_turn = Value(8)
|
||||
self.skip_a_turn = Value("8")
|
||||
|
||||
# How many cards to pick up
|
||||
self.multiple_number = 6
|
||||
pick_up_multiple_suits = [Suit("Spades"), Suit("Clubs")]
|
||||
pick_up_multiple_suits = [Suit("S"), Suit("C")]
|
||||
# Create a BlackJack filter
|
||||
self.pick_up_multiple = Filter(pick_up_multiple_suits, Value("Jack"))
|
||||
self.change_suit = Value("Ace")
|
||||
self.pick_up_multiple = Filter(pick_up_multiple_suits, Value("J"))
|
||||
self.change_suit = Value("A")
|
||||
|
||||
self.specials_all = [self.pick_up_two,
|
||||
self.skip_a_turn,
|
||||
self.pick_up_multiple,
|
||||
self.change_suit]
|
||||
self.specials_power = self.specials_all[:-1]
|
||||
print("Specials all", self.specials_all)
|
||||
print("Power specials", self.specials_power)
|
||||
|
||||
|
||||
def can_play_on_special(bottom_card, card):
|
||||
def can_play_on_special_power(self, bottom_card, card):
|
||||
# If the bottom card is a two
|
||||
if bottom_card == self.pick_up_two:
|
||||
# If the proposed card is not also the same
|
||||
|
@ -162,41 +239,67 @@ class Rules(object):
|
|||
if card == self.pick_up_multiple:
|
||||
return True
|
||||
return False
|
||||
print("Reached final return for can play on special")
|
||||
return False
|
||||
|
||||
def can_play_special_on(self, bottom_card, card):
|
||||
print("CARD IS ", card)
|
||||
print("CHANGE SUIT IS", self.change_suit)
|
||||
if card == self.change_suit:
|
||||
print("Card is change suit")
|
||||
if bottom_card not in self.specials_power:
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_playable_on(bottom_card, card):
|
||||
if bottom_card in self.rules.specials_all:
|
||||
return self.can_play_on_special(bottom_card, card)
|
||||
def is_playable_on(self, bottom_card, card, special):
|
||||
print(f"Is playable on {bottom_card} {card}")
|
||||
if special:
|
||||
if bottom_card in self.specials_power:
|
||||
print("Bottom card in specials all")
|
||||
return self.can_play_on_special_power(bottom_card, card)
|
||||
if card.suit == bottom_card.suit:
|
||||
print("Suit is bottom card suit")
|
||||
return True
|
||||
if card.val == buttom_card.val:
|
||||
if card.val == bottom_card.val:
|
||||
print("Value is bottom card value")
|
||||
return True
|
||||
if special:
|
||||
if card in self.specials_all:
|
||||
print("Card is in specials_all")
|
||||
return self.can_play_special_on(bottom_card, card)
|
||||
|
||||
class Suit(object):
|
||||
def __init__(self, suit):
|
||||
if suit not in "SHDC":
|
||||
raise InvalidSuit
|
||||
self.suit = suit
|
||||
|
||||
def __str__(self):
|
||||
return f"#{self.suit}"
|
||||
return f"{self.suit}"
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def __eq__(self, other):
|
||||
return other.suit == self.suit
|
||||
if isinstance(other, Suit):
|
||||
return self.suit == other.suit
|
||||
elif isinstance(other, Card):
|
||||
return self.suit == other.suit.suit
|
||||
|
||||
class Value(object):
|
||||
def __init__(self, val):
|
||||
self.hash_map = {"J": 11, "Q": 12, "K": 13, "A": 14}
|
||||
string_values = [str(x) for x in range(2, 11)]
|
||||
if val not in self.hash_map.keys() and val not in string_values:
|
||||
raise InvalidCard
|
||||
self.val = val
|
||||
self.numeric_value = self.get_numeric_value(val)
|
||||
|
||||
def get_numeric_value(self, val):
|
||||
hash_map = {"Jack": 11, "Queen": 12, "King": 13, "Ace": 14}
|
||||
if val in hash_map:
|
||||
return hash_map[val]
|
||||
if val in self.hash_map:
|
||||
return self.hash_map[val]
|
||||
else:
|
||||
return val
|
||||
return int(val)
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.numeric_value > other.numeric_value
|
||||
|
@ -207,9 +310,14 @@ class Value(object):
|
|||
def __eq__(self, other):
|
||||
if isinstance(other, Value):
|
||||
return self.numeric_value == other.numeric_value
|
||||
elif isinstance(other, Card):
|
||||
return self.numeric_value == other.val.numeric_value
|
||||
else:
|
||||
print(f"ERROR! Cannot compare {self} and {other}")
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return f".{str(self.val)}"
|
||||
return f"{str(self.val)}"
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
@ -225,37 +333,54 @@ class Filter(object):
|
|||
self.val = val
|
||||
|
||||
def __str__(self):
|
||||
return f"|{self.val} of {self.suits}"
|
||||
return f"|{self.val} of {self.suits}|"
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def __eq__(self, other):
|
||||
print("Filter EQ called")
|
||||
print("other suit", other.suit)
|
||||
print("our suits", self.suits)
|
||||
print("other val", other.val)
|
||||
print("our val", self.val)
|
||||
if other.suit in self.suits and other.val == self.val:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
class Card(object):
|
||||
def __init__(self, suit=None, val=None):
|
||||
self.suit = Suit(suit)
|
||||
self.val = Value(val)
|
||||
print(f"Created card with suit {suit} and value {self.val}")
|
||||
def __init__(self, identifier):
|
||||
self.suit, self.val = Card.identifier_to_card(identifier)
|
||||
|
||||
def playable_on(self, card):
|
||||
pass
|
||||
|
||||
def __str__(self):
|
||||
return f"+({self.val} of {self.suit})"
|
||||
return f"{self.suit}{self.val}"
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.val.numeric_value > other.val.numeric_value
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.val.numeric_value < other.val.numeric_value
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Card):
|
||||
if self.val.numeric_value == other.val.numeric_value:
|
||||
if self.suit.suit == other.suit.suit:
|
||||
return True
|
||||
elif isinstance(other, Value):
|
||||
return self.val.numeric_value == other.numeric_value
|
||||
elif isinstance(other, Suit):
|
||||
return self.suit.suit == other.suit
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def identifier_to_card(identifier):
|
||||
suit_str = identifier[0]
|
||||
val_str = identifier[1:]
|
||||
suit = Suit(suit_str)
|
||||
val = Value(val_str)
|
||||
return suit, val
|
||||
|
||||
@staticmethod
|
||||
def multiple_suit(val, suits):
|
||||
|
@ -265,18 +390,12 @@ class Card(object):
|
|||
card.val = val
|
||||
yield card
|
||||
|
||||
|
||||
mark = Player("Mark")
|
||||
john = Player("John")
|
||||
|
||||
card1 = Card("Spades", "Ace")
|
||||
card2 = Card("Diamonds", "Jack")
|
||||
card4 = Card("Clubs", 3)
|
||||
card5 = Card("Diamonds", 3)
|
||||
card6 = Card("Hearts", 4)
|
||||
|
||||
deck = Deck(card1, card2, card4, card5, card6)
|
||||
deck.shuffle()
|
||||
deck = Deck()
|
||||
deck.fill()
|
||||
#deck.shuffle()
|
||||
|
||||
rules = Rules()
|
||||
|
||||
|
@ -285,26 +404,57 @@ game.add_players(mark, john)
|
|||
|
||||
game.deal()
|
||||
|
||||
print("Mark's cards:", mark.deck.cards)
|
||||
print("Mark's cards:", mark.hand.cards)
|
||||
print("John's cards:", john.hand.cards)
|
||||
|
||||
print("John's cards:", john.deck.cards)
|
||||
print("--- Beginning game ---")
|
||||
while 1:
|
||||
print("=====")
|
||||
current_player = game.current_player
|
||||
print(f"Player {current_player}'s go!")
|
||||
player_cards = current_player.hand.cards
|
||||
last_player = game.last_player
|
||||
if last_player:
|
||||
print(f"Last player: {last_player}")
|
||||
print(f"Last card is: {game.playdeck.last_card}")
|
||||
print(f"Last 5 cards: {game.playdeck.last_cards}")
|
||||
print(f"Your cards: {player_cards}")
|
||||
text = input("~> ")
|
||||
parsed_cards = text.split(",")
|
||||
print("Parsed", parsed_cards)
|
||||
cards_to_play = []
|
||||
for card in parsed_cards:
|
||||
if len(card) == 0:
|
||||
print("Invalid card")
|
||||
continue
|
||||
print("Parsed card iter", card)
|
||||
try:
|
||||
card_to_play = Card(card)
|
||||
print("Card to play", card_to_play)
|
||||
except InvalidCard:
|
||||
print("Invalid card:", card)
|
||||
continue
|
||||
if card_to_play not in current_player.hand.cards:
|
||||
print(f"Card is not in your hand: {card_to_play}")
|
||||
continue
|
||||
print(f"Attempting to play {card_to_play}")
|
||||
played = game.play_card(current_player, card_to_play)
|
||||
if not played:
|
||||
print("Illegal move!")
|
||||
continue
|
||||
if card_to_play == game.rules.change_suit:
|
||||
suit = None
|
||||
while not suit:
|
||||
new_suit = input("Enter a new suit: #> ")
|
||||
try:
|
||||
suit = Suit(new_suit)
|
||||
except InvalidSuit:
|
||||
print(f"Suit {new_suit} is not valid, please select S, H, D or C")
|
||||
continue
|
||||
print(f"Changing last card of {game.playdeck.cards[-1]} to {suit}")
|
||||
game.playdeck.cards[-1].suit = suit
|
||||
|
||||
val1 = Value("Queen")
|
||||
val2 = Value(2)
|
||||
val3 = Value("Queen")
|
||||
assert val1 > val2
|
||||
assert val2 < val1
|
||||
assert val3 == val1
|
||||
|
||||
filter_blackjack = Filter([Suit("Spades"), Suit("Clubs")], Value("Jack"))
|
||||
blackjack1 = Card("Spades", "Jack")
|
||||
blackjack2 = Card("Clubs", "Jack")
|
||||
|
||||
redjack1 = Card("Diamonds", "Jack")
|
||||
redjack2 = Card("Hearts", "Jack")
|
||||
|
||||
assert blackjack1 == filter_blackjack
|
||||
assert blackjack2 == filter_blackjack
|
||||
|
||||
assert redjack1 != filter_blackjack
|
||||
assert redjack2 != filter_blackjack
|
||||
if len(current_player.hand.cards) == 0:
|
||||
print(f"Player {current_player} wins!")
|
||||
print("Thanks for playing!")
|
||||
exit()
|
||||
|
|
Loading…
Reference in New Issue