def test_when_deck_order_cards_and_non_card_passed_then_raise_error(): deck = Deck() cards = [Card("C5"), "Six of Spades", Card("S9")] with raises( ValueError, match= "All objects within cards value must be an instance of the Cards Class" ): deck.order_cards(cards)
def test_when_card_init_and_suit_value_bad_then_raise_error(suit_val): with raises( ValueError, match= f"Card ID first character '{suit_val}' is not within valid list of suit identifiers" ): Card(f"{suit_val}6")
def test_when_card_init_then_correct_values_set(card_val, card_rank, card_suit, card_name, card_id): card = Card(card_id) assert card.name == card_name assert card.identity == card_id assert card.suit == card_suit assert card.rank == card_rank assert card.value == card_val
def cards_five(): return [Card("D3"), Card("DA"), Card("CQ"), Card("H7"), Card("S9")]
def test_when_card_init_and_card_rank_bad_then_raise_error(card_val): with raises(ValueError, match=f"Card ID second character '{card_val}' " f"is not within valid list of rank identifiers"): Card(f"H{card_val}")
def test_when_card_init_and_card_id_not_2_chars_then_raise_error(card_id): with raises(ValueError, match="Card ID provided must be exactly 2 characters long"): Card(card_id)
f"is not within valid list of rank identifiers"): Card(f"H{card_val}") @mark.parametrize("suit_val", [3, "s", "c", "h", "d"]) def test_when_card_init_and_suit_value_bad_then_raise_error(suit_val): with raises( ValueError, match= f"Card ID first character '{suit_val}' is not within valid list of suit identifiers" ): Card(f"{suit_val}6") @mark.parametrize("card_a, card_b, expected", [(Card("D7"), Card("DT"), False), (Card("HQ"), Card("H3"), True), (Card("S3"), Card("CK"), False), (Card("CT"), Card("H4"), True), (Card("H7"), Card("S7"), False)]) def test_when_card_greater_than_then_correct_result_returned( card_a, card_b, expected): actual = card_a > card_b assert actual == expected @mark.parametrize("card_a, card_b, expected", [(Card("D7"), Card("DT"), True), (Card("HQ"), Card("H3"), False), (Card("S3"), Card("CK"), True), (Card("CT"), Card("H4"), False),
def find_odds( self, player_hole_cards: Dict[str, List[Card]], board_cards: List[Card] ): """ Abstract method to implement to find the odds of all players winning from the current situation. :param player_hole_cards: Dictionary, of player names and their hole cards :param board_cards: List of cards representing the current board cards :return: Dictionary of player names and their likelyhood of winning from this situation. """ drawable_cards = self._determine_unused_cards(player_hole_cards, board_cards) player_current_hand = { player: self.find_best_hand(hole_cards, board_cards) for player, hole_cards in player_hole_cards.items() } current_best_hand_rank = max( [best_hand[HAND_RANK] for best_hand in player_current_hand.values()] ) ranked_player_outs = {} for hand_info in self._hand_rankings: for player, current_hand in player_current_hand.items(): if ( current_hand[HAND_RANK] >= hand_info[HAND_RANK] <= current_best_hand_rank ): player_outs = find_outs_scenarios( GAME_TYPE_TEXAS_HOLDEM, hand_info[HAND_TITLE], hole_cards=player_hole_cards[player], board_cards=board_cards, available_cards=drawable_cards, ) if hand_info[HAND_RANK] not in ranked_player_outs.keys(): ranked_player_outs[hand_info[HAND_RANK]] = {player: player_outs} else: ranked_player_outs[hand_info[HAND_RANK]][player] = player_outs utilised_outs = [] wins = {player: 0 for player in player_hole_cards.keys()} for rank, player_out_scenarios in ranked_player_outs.items(): print(f"Assigning wins for rank {rank} outs") players_with_outs = [ player for player, out_scenarios in player_out_scenarios.items() if out_scenarios ] if not players_with_outs: print("No players with outs for this rank") continue elif len(players_with_outs) == 1: player_name = players_with_outs[0] print( f"Only player {player_name} has outs for this rank. Assigning wins" ) potential_outs = [ scenario[OUT_STRING] for scenario in player_out_scenarios[player_name] ] claimed_outs = [ claim_out_string(utilised_outs, out_string, drawable_cards) for out_string in potential_outs ] claimed_outs = [item for sublist in claimed_outs for item in sublist] wins[player_name] += len(claimed_outs) utilised_outs.extend(claimed_outs) else: print( f"Multiple players found to have outs at this rank: {players_with_outs}. Tiebreaking outs." ) combined_outs = {player: [] for player in players_with_outs} for player, out_scenarios in player_out_scenarios.items(): if not out_scenarios: continue for scenario in out_scenarios: scenario["OUTS"] = claim_out_string( utilised_outs, scenario[OUT_STRING], drawable_cards ) combined_outs[player].extend(scenario["OUTS"]) for player, out_scenarios in player_out_scenarios.items(): if not out_scenarios: continue combined_outs[player].sort() my_outs = list(combo for combo, _ in groupby(combined_outs[player])) my_outs = [out for out in my_outs if out not in utilised_outs] their_outs = [ outs for player_name, outs in combined_outs.items() if player_name != player ] their_outs = [item for sublist in their_outs for item in sublist] their_outs.sort() their_outs = list(combo for combo, _ in groupby(their_outs)) their_outs = [out for out in their_outs if out not in utilised_outs] unique_outs = [out for out in my_outs if out not in their_outs] conflicted_outs = [out for out in my_outs if out not in unique_outs] wins[player] += len(unique_outs) utilised_outs.extend(unique_outs) for out_ids in conflicted_outs: valid_players = [ player_name for player_name, outs in combined_outs.items() if out_ids in outs ] tiebreakers = {} hole_cards = {} for player in valid_players: tiebreakers[player] = [ scenario[TIEBREAKER] for scenario in player_out_scenarios[player] if out_ids in scenario["OUTS"] ][0] hole_cards[player] = player_hole_cards[player] drawn_cards = [Card(card_id) for card_id in out_ids] kwarg_set = TB_DRAWS_KWAGRS[self._hand_rankings[HAND_TITLE]] kwargs = { TB_DRAWS_KWARGS_ALL: { "tiebreakers": tiebreakers, "hole_cards": hole_cards, "board_cards": board_cards, "drawn_cards": drawn_cards, }, TB_DRAWS_KWARGS_TIEBREAKER: {"tiebreakers": tiebreakers}, }[kwarg_set] winner = tiebreak_outs_draw( GAME_TYPE_TEXAS_HOLDEM, hand_info[HAND_TITLE], **kwargs ) if winner not in wins.keys(): wins[winner] = 1 else: wins[winner] += 1 utilised_outs.append(out_ids) draw_combo_num = 1 cards_to_draw = 5 - len(board_cards) for draw in range(cards_to_draw): cards_available = len(drawable_cards) - draw draw_combo_num *= cards_available draw_combo_num /= cards_to_draw odds = { player: win_count / draw_combo_num for player, win_count in wins.items() } return odds