def _get_flush_hands(self):
        upcard_nums = self.upcard_nums()

        card_suit_locations = {}
        for r in range(3):
            for c in range(3):
                upcard = int_to_card(upcard_nums[r][c])
                if upcard is not None:
                    upcard_suit = SUITS[upcard.suit_idx()]
                    if upcard_suit not in card_suit_locations:
                        card_suit_locations[upcard_suit] = []
                    card_suit_locations[upcard_suit].append((r, c))

        flush_suits = set([])
        for card_suit in card_suit_locations:
            if len(card_suit_locations[card_suit]) >= 5:
                flush_suits.add(card_suit)
        # print(f"flush_suits = {flush_suits}")

        flush_hands = []
        for flush_suit in flush_suits:
            suit_locations = card_suit_locations[flush_suit]
            hands = itertools.combinations(suit_locations, 5)
            flush_hands.extend([set(hand) for hand in hands])

        # print(f"flush_hands = {flush_hands}")
        return flush_hands
    def _get_quad_hands(self):
        upcard_nums = self.upcard_nums()

        card_rank_locations = {}
        for r in range(3):
            for c in range(3):
                upcard = int_to_card(upcard_nums[r][c])
                if upcard is not None:
                    upcard_rank = RANKS[upcard.rank_idx()]
                    if upcard_rank not in card_rank_locations:
                        card_rank_locations[upcard_rank] = []
                    card_rank_locations[upcard_rank].append((r, c))

        quad_ranks = set([])
        for card_rank in card_rank_locations:
            if len(card_rank_locations[card_rank]) >= 4:
                quad_ranks.add(card_rank)
        # print(f"quad_ranks = {quad_ranks}")

        quad_hands = []
        for quad_rank in quad_ranks:
            rank_locations = card_rank_locations[quad_rank]
            hands = itertools.combinations(rank_locations, 4)
            quad_hands.extend([set(hand) for hand in hands])

        # the chosen piles must not all be on the same row
        quad_hands = self._ignore_invalid_hands(quad_hands)

        # print(f"quad_hands = {quad_hands}")
        return quad_hands
    def _get_pair_hands(self):
        """
        Returns a list of hands, represented as sets of tuples, where each tuple
        is the location of a card in the hand.
        """
        upcard_nums = self.upcard_nums()

        card_rank_locations = {}
        for r in range(3):
            for c in range(3):
                upcard = int_to_card(upcard_nums[r][c])
                if upcard is not None:
                    upcard_rank = RANKS[upcard.rank_idx()]
                    if upcard_rank not in card_rank_locations:
                        card_rank_locations[upcard_rank] = []
                    card_rank_locations[upcard_rank].append((r, c))

        pair_ranks = set([])
        for card_rank in card_rank_locations:
            if len(card_rank_locations[card_rank]) >= 2:
                pair_ranks.add(card_rank)
        # print(f"pair_ranks = {pair_ranks}")

        pair_hands = []
        for pair_rank in pair_ranks:
            rank_locations = card_rank_locations[pair_rank]
            hands = itertools.combinations(rank_locations, 2)
            pair_hands.extend([set(hand) for hand in hands])

        # the chosen piles must not all be on the same row
        pair_hands = self._ignore_invalid_hands(pair_hands)

        # print(f"pair_hands = {pair_hands}")
        return pair_hands
    def full_info(self):
        # Print full game state info (including the hidden cards)
        repr = (f"LUCKY SUIT = {SUITS[self.lucky_suit_idx]}\n"
                f"DISCARDS LEFT = {self.discards_remaining}\n"
                f"GAME OVER? = {self.is_game_over()}\n")
        upcard_nums = self.upcard_nums()
        pile_sizes = self.pile_sizes()
        # Print board/piles state
        for r in range(3):
            for c in range(3):
                pile_repr = f"pile ({r}, {c}): "
                if not self.is_pile_empty(r, c):
                    pile_cards = [
                        int_to_card(card_num)
                        for card_num in self.card_num_piles[r][c]
                    ]
                    pile_repr += str(pile_cards)
                else:
                    pile_repr += "(EMPTY PILE)"
                pile_repr += "\n"
                repr += pile_repr

        # Print dead cards
        repr += f"DEAD CARDS = {[int_to_card(card_num) for card_num in self.dead_card_nums]}"
        return repr
    def _is_lucky_hand(self, piles):
        upcard_nums = self.upcard_nums()

        for pile in piles:
            pile_row, pile_col = pile
            assert not self.is_pile_empty(pile_row, pile_col)
            card = int_to_card(upcard_nums[pile_row][pile_col])

            if card.suit == self.lucky_suit:
                return True
        return False
    def _get_full_house_hands(self):
        upcard_nums = self.upcard_nums()

        card_rank_locations = {}
        for r in range(3):
            for c in range(3):
                upcard = int_to_card(upcard_nums[r][c])
                if upcard is not None:
                    upcard_rank = RANKS[upcard.rank_idx()]
                    if upcard_rank not in card_rank_locations:
                        card_rank_locations[upcard_rank] = []
                    card_rank_locations[upcard_rank].append((r, c))

        pair_ranks = set([])
        trip_ranks = set([])
        for card_rank in card_rank_locations:
            if len(card_rank_locations[card_rank]) >= 2:
                pair_ranks.add(card_rank)
            if len(card_rank_locations[card_rank]) >= 3:
                trip_ranks.add(card_rank)

        full_house_rank_pairs = set([])
        for trip_rank in trip_ranks:
            for pair_rank in pair_ranks:
                if pair_rank == trip_rank:
                    continue
                full_house_ranks = (trip_rank, pair_rank)
                full_house_rank_pairs.add(full_house_ranks)
        # print(f"full_house_rank_pairs = {full_house_rank_pairs}")

        full_house_hands = []
        for trip_rank, pair_rank in full_house_rank_pairs:
            trip_rank_locations = card_rank_locations[trip_rank]
            pair_rank_locations = card_rank_locations[pair_rank]
            trip_hands = itertools.combinations(trip_rank_locations, 3)
            pair_hands = itertools.combinations(pair_rank_locations, 2)
            full_house_combos = itertools.product(trip_hands, pair_hands)
            for combo in full_house_combos:
                hand = set(combo[0]).union(set(combo[1]))
                if len(hand) != 5:
                    continue
                full_house_hands.append(hand)

        # the chosen piles must not all be on the same row
        full_house_hands = self._ignore_invalid_hands(full_house_hands)

        # print("full_house_hands: ")
        # pprint(full_house_hands)
        return full_house_hands
예제 #7
0
def short_repr_gamestate(gamestate: GameState) -> str:
    board_repr = ""
    upcard_nums = gamestate.upcard_nums()
    for r in range(3):
        for c in range(3):
            if not gamestate.is_pile_empty(r, c):
                upcard = int_to_card(upcard_nums[r][c])
                board_repr += str(upcard) + " "
            else:
                board_repr += "-- "
        if r != 2:
            board_repr += "/ "
        else:
            board_repr += "; "
    board_repr += f"Discards = {gamestate.discards_remaining}, Lucky suit = {gamestate.lucky_suit}"
    board_repr += "\n"
    return board_repr
    def _get_straight_flush_hands(self):
        upcard_nums = self.upcard_nums()

        lg_straight_hands = self._get_lg_straight_hands()

        straight_flush_hands = []
        for hand in lg_straight_hands:
            hand_suit = None
            valid_hand = True
            for location in hand:
                row, col = location
                card = int_to_card(upcard_nums[row][col])
                if hand_suit is None:
                    hand_suit = card.suit
                elif card.suit != hand_suit:
                    valid_hand = False
            if valid_hand:
                straight_flush_hands.append(hand)

        # print(f"straight_flush_hands = {straight_flush_hands}")
        return straight_flush_hands
    def _get_lg_straight_hands(self):
        upcard_nums = self.upcard_nums()

        card_rank_locations = {}
        for r in range(3):
            for c in range(3):
                upcard = int_to_card(upcard_nums[r][c])
                if upcard is not None:
                    upcard_rank = RANKS[upcard.rank_idx()]
                    if upcard_rank not in card_rank_locations:
                        card_rank_locations[upcard_rank] = []
                    card_rank_locations[upcard_rank].append((r, c))

        wrapping_card_ranks = [
            "A", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K",
            "A"
        ]

        # looking for 5-straights, check every rank for a possible low-end of the straight: A to T (A-2-3-4-5 to T-J-Q-K-A)
        lg_straight_hands = []
        for rank_idx in range(len(wrapping_card_ranks) - (5 - 1)):
            straight_ranks = wrapping_card_ranks[rank_idx:rank_idx + 5]
            straight_possible = True
            for rank in straight_ranks:
                if rank not in card_rank_locations or len(
                        card_rank_locations[rank]) == 0:
                    straight_possible = False
            if not straight_possible:
                continue
            straight_rank_locations = [
                card_rank_locations[rank] for rank in straight_ranks
            ]
            hands = itertools.product(*straight_rank_locations)
            lg_straight_hands.extend([set(hand) for hand in hands])

        # the chosen piles must not all be on the same row
        lg_straight_hands = self._ignore_invalid_hands(lg_straight_hands)

        # print(f"lg_straight_hands = {lg_straight_hands}")
        return lg_straight_hands
    def __repr__(self):
        # Print general game state info
        repr = (f"LUCKY SUIT = {SUITS[self.lucky_suit_idx]}\n"
                f"DISCARDS LEFT = {self.discards_remaining}\n"
                f"GAME OVER? = {self.is_game_over()}\n")
        upcard_nums = self.upcard_nums()
        pile_sizes = self.pile_sizes()
        # Print board/piles state
        for r in range(3):
            row_repr = "| "
            for c in range(3):
                if not self.is_pile_empty(r, c):
                    upcard = int_to_card(upcard_nums[r][c])
                    row_repr += str(
                        upcard) + f"(+{int(pile_sizes[r][c] - 1)})" + " | "
                else:
                    row_repr += "--(+0) | "
            row_repr += "\n"
            repr += row_repr

        # Print dead cards
        repr += f"DEAD CARDS = {[int_to_card(card_num) for card_num in self.dead_card_nums]}"
        return repr