diff --git a/blackjack.py b/blackjack.py new file mode 100755 index 0000000..53e8d38 --- /dev/null +++ b/blackjack.py @@ -0,0 +1,310 @@ +#!/usr/bin/env python3 +import random + +class NoMoreCards(Exception): + pass + +class Game(object): + def __init__(self, deck, rules): + self.players = [] + self.drawdeck = deck + self.playdeck = Deck() + self.rules = rules + + # Which index player's turn is it? + self.player_index = 0 + print("Created game.") + + def next_turn(self): + current_player = self.players[self.current_player] + 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}") + self.current_player = 0 + else: + self.current_player += 1 + print(f"Incrementing current_player: {self.players}, {self.current_player}") + + def add_players(self, *players): + for player in players: + print(f"Adding player: {player}") + self.players.append(player) + + 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) + if self.rules.flipcard: + first_card = self.drawdeck.draw() + print(f"First card is: {first_card}") + self.playdeck.put(first_card) + + def play_card(self, player, card): + 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) + print("Card is playable", is_playable) + #current_card = self.d + +class Player(object): + def __init__(self, name): + self.name = name + self.deck = Hand() + print(f"Created player {name}") + + def __str__(self): + return self.name + + def __repr__(self): + return self.__str__() + +class SetOfCards(object): + def __init__(self, *cards): + 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): + for i in range(0, num): + 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) + +class Deck(SetOfCards): + def shuffle(self): + random.shuffle(self.cards) + print(f"Shuffled deck: {self.cards}") + + @property + def last_card(self): + if self.cards: + return self.cards[-1] + else: + raise NoMoreCards + +class Hand(SetOfCards): + pass + +class Rules(object): + def __init__(self): + self.initial_cards = 2 # 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) + # Next player has to skip a go if they don't have another + self.skip_a_turn = Value(8) + + # How many cards to pick up + self.multiple_number = 6 + pick_up_multiple_suits = [Suit("Spades"), Suit("Clubs")] + # Create a BlackJack filter + self.pick_up_multiple = Filter(pick_up_multiple_suits, Value("Jack")) + self.change_suit = Value("Ace") + + 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): + # If the bottom card is a two + if bottom_card == self.pick_up_two: + # If the proposed card is not also the same + if card == self.pick_up_two: + return True + if self.jacks_on_twos: + if card == self.pick_up_mutiple: + return True + # We can only play 2s or Jacks if that is enabled + return False + # if the bottom card is a two + if bottom_card == self.skip_a_turn: + # if the proposed card is not also the same + if card == self.skip_a_turn: + return True + if self.jacks_on_eights: + # If the proposed card is a blackjack + if card == self.pick_up_multiple: + return True + # We can only play 8s or Jacks if that is enabled + return False + # If the bottom card is a Blackjack + if bottom_card == self.pick_up_multiple: + # If the card is the other Blackjack + if card == self.pick_up_multiple: + return True + return False + 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) + if card.suit == bottom_card.suit: + return True + if card.val == buttom_card.val: + return True + +class Suit(object): + def __init__(self, suit): + self.suit = suit + + def __str__(self): + return f"#{self.suit}" + + def __repr__(self): + return self.__str__() + + def __eq__(self, other): + return other.suit == self.suit + +class Value(object): + def __init__(self, val): + 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] + else: + return val + + def __gt__(self, other): + return self.numeric_value > other.numeric_value + + def __lt__(self, other): + return self.numeric_value < other.numeric_value + + def __eq__(self, other): + if isinstance(other, Value): + return self.numeric_value == other.numeric_value + + def __str__(self): + return f".{str(self.val)}" + + def __repr__(self): + return self.__str__() + + @staticmethod + def multiple(*vals): + for val in vals: + yield Value(val) + +class Filter(object): + def __init__(self, suits, val): + self.suits = suits + self.val = val + + def __str__(self): + 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 playable_on(self, card): + pass + + def __str__(self): + return f"+({self.val} of {self.suit})" + + def __repr__(self): + return self.__str__() + + + @staticmethod + def multiple_suit(val, suits): + for suit in suits: + card = Card() + card.suit = suit + 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() + +rules = Rules() + +game = Game(deck, rules) +game.add_players(mark, john) + +game.deal() + +print("Mark's cards:", mark.deck.cards) + +print("John's cards:", john.deck.cards) + +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