def _init_hand(self, buy_in: int = 1): """This initializes a hand of blackjack with a minimum buy-in of :param buy_in dollars.""" # zeroth check to make sure buy_in denom is in the standard chip denoms buy_in_key = ChipStack.get_chip_string(buy_in) if buy_in_key not in ChipStack.get_empty_stack().keys(): raise KeyError( 'The buy-in value of \'{}\' is not in the standard denominations' .format(buy_in_key)) # also discard any cards in the hand already self.dealer.discard( self.discard_pile, [x.name for x in self.dealer.hand]) # TODO: refactor this... for player in self.players.values(): player.discard(self.discard_pile, [x.name for x in player.hand]) # first check if all players want to buy-in to the hand self.dealt_in_players = list( self.players.keys()) # deal in all players initially self.take_bets(min_bet=buy_in) # second deal hands to all players that are still dealt-in self.deal_cards(list(self.players.values()), n_cards=2, n_visible=2) # two face up self.deal_cards([self.dealer], n_cards=1, n_visible=1) # one face up self.deal_cards([self.dealer], n_cards=1, n_visible=0) # one face down # print out the hands for all players and their bets for player_name in self.dealt_in_players: self.players[player_name].view_hand(all_visible=True) self.dealer.view_hand() # lastly check for any naturals or busts before moving to game loop self.check_for_payouts(end_of_hand=False) return # move to the next state of gameplay
def __init__(self, name: str = '', chips: Optional[ChipStack] = None, hand: Optional[CardHand] = None, pot: Optional[ChipStack] = None, action_set: Optional[ActionSet] = None) -> None: self.name: str = name if chips is None: chips = ChipStack() if hand is None: hand = CardHand() if pot is None: pot = ChipStack() self.pot = pot # unless there is a shared pot object passed in, each player instance gets its own pot instance self.chips: ChipStack = chips # empty stack unless otherwise specified self._player_hand: CardHand = hand if action_set is None: action_set = { 'actions_basic': # load only a basic set of instance methods for actions { 'view-hand': self.view_hand, 'draw': self.draw, 'discard': self.discard, 'transfer': self.transfer } } self.action_set: ActionSet = action_set
def __init__(self): # Setup the Players self.dealer: Player = Player(name='dealer', chips=ChipStack.from_dealer_stack()) self.players: Dict[str, Player] = { 'human': Player('human', ChipStack.from_standard_stack()) } self.dealt_in_players: List[str] = list( self.players.keys()) # deal-in all players initially # Setup the Decks self.draw_pile: CardPile = CardPile.from_standard_deck() self.draw_pile.shuffle() self.discard_pile: CardPile = CardPile()
def test_filled_stack_from_amount(self): target = { '$1': 1, '$5': 1, '$10': 1, '$20': 0, '$25': 1, '$50': 1, '$100': 1 } temp = ChipStack.filled_stack_from_amount( ChipStack.get_stack_value(target)) for key in temp.keys(): self.assertEqual(temp[key], target[key])
def test_transfer_chips_all(self): cs1 = ChipStack.from_standard_stack() cs2 = ChipStack() std_stack = cs1.stack.copy() empty_stack = cs2.stack.copy() # transfer everything from cs1 to cs2 cs1.transfer_chips(cs2, cs1.stack) self.assertEqual(cs1.stack, empty_stack) self.assertEqual(cs2.stack, std_stack) # transfer emptied stack to cs2 again cs1.transfer_chips(cs2, cs1.stack) self.assertEqual(cs1.stack, empty_stack) self.assertEqual(cs2.stack, std_stack) # try to transfer a standard_stack from cs1 to cs2 again self.assertRaises(ValueError, cs1.transfer_chips, cs2, std_stack)
def check_for_payout(self, player: Player) -> bool: """ This function checks to see if a single player (not a dealer) has gotten blackjack or busted. If they have, then return out_of_game=True for 'removal from dealt-in players logic' """ out_of_game: bool = False (is_blackjack, payout_rate) = BlackJack.is_blackjack(player) if is_blackjack: # Dealer pays out to the player # assume rounding down is house cut payout_value: int = int(payout_rate * player.pot.stack_value) n_payout_chips: Dict[str, int] = ChipStack.get_chips_from_amount( payout_value, denom_pref='high') self.dealer.payout_chips(player.pot, n_payout_chips) # Remove player from dealt_in list self.dealt_in_players.remove(player.name) print('{0} has gotten blackjack and wins ${1}'.format( player.name, payout_value)) out_of_game = True elif BlackJack.is_bust(player): # Player pays out to dealer player.payout_all(self.dealer.pot) # Remove player from dealt_in list self.dealt_in_players.remove(player.name) print('{0} has busted and loses ${1}'.format( player.name, player.pot.stack_value)) out_of_game = True return out_of_game
def test_get_empty_stack(self): empty = { '$1': 0, '$5': 0, '$10': 0, '$20': 0, '$25': 0, '$50': 0, '$100': 0 } self.assertEqual(ChipStack.get_empty_stack(), empty)
def test_transfer_chips_sample(self): sample = {'$1': 0, '$5': 5, '$10': 3} cs1 = ChipStack(sample) cs2 = ChipStack() sample_stack = cs1.stack.copy() empty_stack = cs2.stack.copy() # transfer everything from cs1 to cs2 cs1.transfer_chips(cs2, cs1.stack) self.assertEqual(cs1.stack, empty_stack) self.assertEqual(cs2.stack, sample_stack) # transfer everything back cs2.transfer_chips(cs1, cs2.stack) self.assertEqual(cs1.stack, sample_stack) self.assertEqual(cs2.stack, empty_stack)
def test_init_from_amount(self): target = { '$1': 1, '$5': 1, '$10': 1, '$20': 0, '$25': 1, '$50': 1, '$100': 1 } cs = ChipStack.from_amount(amount=191) for key in cs.stack.keys(): self.assertEqual(cs.stack[key], target[key])
def test_standard_stack_init(self): std = { '$1': 25, '$5': 5, '$10': 3, '$20': 1, '$25': 0, '$50': 2, '$100': 1 } cs = ChipStack.from_standard_stack() for key in cs.stack.keys(): self.assertEqual(cs.stack[key], std[key])
def test_init_from_dealer(self): dealer = { '$1': 1000, '$5': 1000, '$10': 1000, '$20': 1000, '$25': 1000, '$50': 1000, '$100': 1000 } cs = ChipStack.from_dealer_stack() self.assertEqual(cs.name, 'dealer') for key in cs.stack.keys(): self.assertEqual(cs.stack[key], dealer[key])
def test_exchange_chips(self): cs = ChipStack.from_standard_stack() # exchange all 3 $10 chips for 30 $1 chips (all chips) cs.exchange_chips('$10', '$1') self.assertEqual(cs.stack['$10'], 0) self.assertEqual(cs.stack['$1'], 55) # exchange all 3 $10 chips for 30 $1 chips (all chips) cs.exchange_chips('$50', '$10', 1) self.assertEqual(cs.stack['$50'], 1) self.assertEqual(cs.stack['$10'], 5) # try to exchange 25 $1 chips for 1 $50 and get error self.assertRaises(ValueError, cs.exchange_chips, '$1', '$50', 25) # exchange all 55 $1 chips for 1 $50 chips (all chips) cs.exchange_chips('$1', '$50') self.assertEqual(cs.stack['$50'], 2) self.assertEqual(cs.stack['$1'], 5) # try to exchange chips for bad denominations self.assertRaises(KeyError, cs.exchange_chips, '$1', '#50') self.assertRaises(KeyError, cs.exchange_chips, '#1', '$50')
def test_add_amount_of_chips(self): # Test a simple case cs = ChipStack() cs.add_amount_of_chips(amount=201) # sum of all the keys self.assertEqual(cs.stack['$1'], 1) # 201 -> $1: 1 and $5: 40 self.assertEqual(cs.stack['$5'], 0) # 200 -> $5: 0 and $10: 20 self.assertEqual(cs.stack['$10'], 0) # 200 -> $10: 0 and $20: 10 self.assertEqual(cs.stack['$20'], 0) # 200 -> $20: 0 and $25: 8 self.assertEqual(cs.stack['$25'], 0) # 200 -> $25: 0 and $50: 4 self.assertEqual(cs.stack['$50'], 0) # 200 -> $50: 0 and $100: 2 self.assertEqual(cs.stack['$100'], 2) # Test a case when adding the remainder of an exchange # NOTE: once the amount has been deposited into the lowest chip denoms, do not sort into higher as side effect cs = ChipStack({'$5': 0, '$10': 7, '$25': 0}) remainder = 5 cs.add_amount_of_chips(remainder) self.assertEqual(cs.stack['$1'], 0) # 5 of $1 goes to 1 of $5 self.assertEqual(cs.stack['$5'], 1) # stays self.assertEqual(cs.stack['$10'], 7) self.assertEqual(cs.stack['$20'], 0) self.assertEqual(cs.stack['$25'], 0) self.assertEqual(cs.stack['$50'], 0) self.assertEqual(cs.stack['$100'], 0)
def test_remove_chips(self): # create a std stack and remove another empty stack cs = ChipStack.from_standard_stack() empty_stack = { '$1': 0, '$5': 0, '$10': 0, '$20': 0, '$25': 0, '$50': 0, '$100': 0 } std_stack = cs.stack.copy() cs._remove_chips(empty_stack) self.assertEqual(cs.stack, std_stack) self.assertNotEqual(cs.stack, empty_stack) # remove a std stack from the std stack to see if empty cs._remove_chips(std_stack) self.assertEqual(cs.stack, empty_stack) # prevent chip quantities from going negative # see https://stackoverflow.com/questions/129507/how-do-you-test-that-a-python-function-throws-an-exception self.assertRaises(ValueError, cs._remove_chips, std_stack)
def test_add_chips(self): # create an empty stack and add another empty stack cs = ChipStack() empty_stack = { '$1': 0, '$5': 0, '$10': 0, '$20': 0, '$25': 0, '$50': 0, '$100': 0 } stack = cs.stack.copy() cs._add_chips(empty_stack) self.assertEqual(cs.stack, stack) self.assertEqual(cs.stack, empty_stack) # create an standard stack and add its stack to cs2 = ChipStack.from_standard_stack() cs._add_chips(cs2.stack) self.assertEqual(cs.stack, cs2.stack)
def test_exchange_chips_with_remainders(self): cs = ChipStack() cs._add_chips({'$25': 3}) cs.exchange_chips('$25', '$10') self.assertEqual(cs.stack['$10'], 7) self.assertEqual(cs.stack['$5'], 1) cs.stack = ChipStack.get_empty_stack() cs._add_chips({'$20': 6}) cs.exchange_chips('$20', '$50') self.assertEqual(cs.stack['$50'], 2) self.assertEqual(cs.stack['$20'], 1)
def test_get_stack_value(self): cs = ChipStack.from_standard_stack() self.assertEqual(300, ChipStack.get_stack_value(cs.stack))
def check_for_payouts(self, end_of_hand: bool = False) -> None: """ This function checks to see all players have gotten blackjack or busted. If they have, then they are removed from the dealt-in players list and payouts go accordingly. Additionally, if its the end of the hand, the scores vs. the dealer are checked and paid put """ max_dealer_hand_value: int = max(BlackJack.get_hand_value(self.dealer)) dealer_busted: bool = True if max_dealer_hand_value > 21 else False for player_name in self.dealt_in_players: if end_of_hand: # This will be used later for checking payouts at the end of a hand max_player_hand_value: int = max( BlackJack.get_hand_value(self.players[player_name])) out_of_game = self.check_for_payout(self.players[player_name]) if out_of_game: continue # don't continue to check other conditions if end_of_hand and (max_player_hand_value > max_dealer_hand_value or dealer_busted): # Dealer pays out to the player # assume rounding down is house cut payout_value: int = int( 1.5 * self.players[player_name].pot.stack_value) n_payout_chips: Dict[str, int] = ChipStack.get_chips_from_amount( payout_value, denom_pref='high') self.dealer.payout_chips(self.players[player_name].pot, n_payout_chips) # Remove player from dealt_in list self.dealt_in_players.remove(player_name) # Print the results self.players[player_name].view_hand(self.dealer, all_visible=True) if dealer_busted: print('Dealer busts so {0} wins ${1}'.format( player_name, payout_value)) else: print('{0} beat the dealer and wins ${1}'.format( player_name, payout_value)) elif end_of_hand and not dealer_busted and (max_player_hand_value < max_dealer_hand_value): # Player pays out to dealer self.players[player_name].payout_all(self.dealer.pot) # Remove player from dealt_in list self.dealt_in_players.remove(player_name) # Print the results self.players[player_name].view_hand(self.dealer, all_visible=True) print( 'Dealer did not bust and beats {0}\'s hand. {0} loses ${1}' .format(player_name, self.players[player_name].bet_value)) elif end_of_hand and not dealer_busted and ( max_player_hand_value == max_dealer_hand_value): # Player does not lose their money, but doesn't get paid out. self.players[player_name].payout_all( self.players[player_name].pot) # return the money from pot # Remove player from dealt_in list self.dealt_in_players.remove(player_name) print('Dealer ties {0}\'s hand. {0} is returned ${1}'.format( player_name, self.players[player_name].bet_value))
def test_stack_init_sample(self): sample = {'$1': 0, '$5': 5, '$10': 3} cs = ChipStack(sample) for key in cs.stack.keys(): self.assertEqual(cs.stack[key], sample.get(key, 0))
def test_get_chip_value(self): self.assertEqual(5, ChipStack.get_chip_value('$5')) self.assertRaises(KeyError, ChipStack.get_chip_value, '##20$')
def test_get_chip_string(self): self.assertEqual('$20', ChipStack.get_chip_string(20)) self.assertRaises(ValueError, ChipStack.get_chip_string, 11)
def test_empty_init(self): cs = ChipStack(stack=None) for key in cs.stack.keys(): self.assertEqual(cs.stack[key], 0)