Exemplo n.º 1
0
    def check_for_play_tip(self, round_info, player_number, hint_pass_score=0.9, double_hint_multiplier=0.3,
                           false_tip_penalty=-2.5, distance_to_player_multiplier=1.01, lower_rank_multiplier=1.07,
                           information_tip_value=0.2, already_has_play_multiplier=0.5, chain_bonus_multiplier=1.3,
                           only_next_player=False):
        if round_info.hints <= 1:
            return False

        original_player_number = player_number
        if player_number is round_info.player_turn:
            original_player_hand = round_info.player_hand
        else:
            original_player_hand = utils.get_player_hand_by_number(round_info, player_number)

        player_number = utils.next_player_number(round_info, original_player_number)
        worth_hinting = {}
        predicted_board_state = {original_player_number: deepcopy(round_info.board_state)}

        while player_number is not original_player_number:
            predicted_board_state[player_number] = deepcopy(
                predicted_board_state[utils.prev_player_number(round_info, player_number)])
            worth_hinting[player_number] = False

            play = self.check_for_obvious_play(round_info, player_number)
            if play is False:
                play = self.check_for_hinted_play(round_info, player_number)
                if play is False:
                    worth_hinting[player_number] = True
            if play is not False:
                player_hand = utils.get_player_hand_by_number(round_info, player_number)
                suit = player_hand[play[1]].real_suit
                rank = player_hand[play[1]].real_rank
                if predicted_board_state[player_number][suit] is rank.value - 1:
                    predicted_board_state[player_number][suit] += 1

            player_number = utils.next_player_number(round_info, player_number)

        player_number = original_player_number
        hinted_plays = {}
        first_time = True

        while player_number is not original_player_number or first_time:
            first_time = False
            hinted_plays[player_number] = {}
            for suit in utils.Suit:
                hinted_plays[player_number][suit] = {}
                for rank in utils.Rank:
                    hinted_plays[player_number][suit][rank] = 0
            player_number = utils.next_player_number(round_info, player_number)

        player_number = utils.next_player_number(round_info, original_player_number)
        for card in original_player_hand:
            if card.revealed_rank is not None and card.revealed_suit is not None and \
                    round_info.board_state[card.real_suit] < card.real_rank.value:
                hinted_plays[original_player_number][card.real_suit][card.real_rank] += 1

        while player_number is not original_player_number:
            player_hand = utils.get_player_hand_by_number(round_info, player_number)
            for card in player_hand:
                if round_info.board_state[card.real_suit] < card.real_rank.value and \
                        (card.revealed_rank is not None or card.revealed_suit is not None):
                    hinted_plays[player_number][card.real_suit][card.real_rank] += 1
            player_number = utils.next_player_number(round_info, player_number)

        player_number = utils.next_player_number(round_info, original_player_number)
        potential_playable_ranks = {}
        potential_playable_suits = {}

        while player_number is not original_player_number:
            potential_playable_ranks[player_number] = {}
            potential_playable_suits[player_number] = {}
            for rank in utils.Rank:
                potential_playable_ranks[player_number][rank] = []
            for suit in utils.Suit:
                potential_playable_suits[player_number][suit] = []

            player_hand = utils.get_player_hand_by_number(round_info, player_number)
            for card in player_hand:
                if card.revealed_suit is None:
                    potential_playable_suits[player_number][card.real_suit].append(card)
                if card.revealed_rank is None:
                    potential_playable_ranks[player_number][card.real_rank].append(card)

            player_number = utils.next_player_number(round_info, player_number)

        max_player_number = 0
        max_potential = -5
        max_hint = 0

        known = {}
        for suit in utils.Suit:
            known[suit] = {}
            for rank in utils.Rank:
                known[suit][rank] = 0

        for card in original_player_hand:
            if card.revealed_rank is not None and card.revealed_suit is not None:
                known[card.revealed_suit][card.revealed_rank] += 1

        for hand in round_info.other_players_hands:
            if original_player_number is not hand.player_number:
                for card in hand:
                    known[card.real_suit][card.real_rank] += 1

        def check_card_potential(card, player, board_state, current_rank=None, pure_info=False):
            player_distance = player - original_player_number - 1
            if player_distance < 0:
                player_distance += round_info.number_of_players

            already_hinted = False
            if card.revealed_suit is None and card.revealed_rank is None:
                for players in hinted_plays:
                    if hinted_plays[players][card.real_suit][card.real_rank] != 0:
                        already_hinted = True

            card_potential = pow(distance_to_player_multiplier, player_distance) *\
                             pow(lower_rank_multiplier, 5 - card.real_rank.value)

            if (card.revealed_suit is not None or card.revealed_rank is not None) and \
                    card.real_rank.value - board_state[card.real_suit] <= 1 and \
                    self.card_hint_type[player][card.hand_position] == "Play":
                card_potential *= double_hint_multiplier

            if card.real_rank.value <= 4 and card.real_rank.value - board_state[card.real_suit] == 1 and \
                    known[card.real_suit][utils.Rank(card.real_rank.value + 1)] > 0:
                card_potential *= chain_bonus_multiplier

            if already_hinted:
                card_potential += false_tip_penalty

            if pure_info \
                    or (max(round_info.board_state.values()) < card.real_rank.value - 1 and current_rank is None) \
                    or (self.card_hint_type[player][card.hand_position] == "Information"):

                card_potential = information_tip_value * pow(distance_to_player_multiplier, player_distance) * \
                                 pow(lower_rank_multiplier, card.real_rank.value - 1)

                if not already_hinted and \
                        card.real_rank.value - board_state[card.real_suit] == 1 and \
                        self.card_hint_type[player][card.hand_position] == "Information":
                    card_potential = pow(distance_to_player_multiplier, player_distance) * \
                                     pow(lower_rank_multiplier, 5 - card.real_rank.value)

                if card.real_rank.value <= 4 and card.real_rank.value - board_state[card.real_suit] == 1 and \
                        known[card.real_suit][utils.Rank(card.real_rank.value + 1)] > 0:
                    card_potential *= chain_bonus_multiplier

            elif (card.revealed_suit is None and card.revealed_rank is None) and \
                    ((current_rank is None and board_state[card.real_suit] is not card.real_rank.value - 1) or
                     (current_rank is not None and card.real_rank.value is not current_rank)):
                card_potential += false_tip_penalty

            if current_rank is not None and card.real_rank.value is current_rank:
                current_rank += 1

            return card_potential, current_rank

        for player in potential_playable_ranks:
            if debug and round_info.log:
                self.info('{0}'.format(player))

            info_rank = None
            info_suit = None
            player_distance = player - original_player_number - 1
            if player_distance < 0:
                player_distance += round_info.number_of_players

            if player_distance == 0 or not only_next_player:
                if player_distance == 0:
                    play = self.check_for_hinted_play(round_info, player)
                    target_hand = utils.get_player_hand_by_number(round_info, player)
                    if play is not False:
                        if target_hand[play[1]].revealed_rank is None:
                            info_rank = target_hand[play[1]].real_rank
                        if target_hand[play[1]].revealed_suit is None:
                            info_suit = target_hand[play[1]].real_suit
                    else:
                        play = self.check_for_guess_discard(round_info, player)
                        if target_hand[play[1]].revealed_rank is None:
                            info_rank = target_hand[play[1]].real_rank
                        if target_hand[play[1]].revealed_suit is None:
                            info_suit = target_hand[play[1]].real_suit

                for rank in potential_playable_ranks[player]:
                    board_state = deepcopy(predicted_board_state[utils.prev_player_number(round_info, player)])
                    potential = 0
                    for card in potential_playable_ranks[player][rank]:
                        if rank is not info_rank:
                            answer = check_card_potential(card, player, board_state)[0]
                        else:
                            answer = check_card_potential(card, player, board_state, pure_info=True)[0]
                        if answer >= pow(distance_to_player_multiplier, player_distance) * \
                                     pow(lower_rank_multiplier, 5 - card.real_rank.value):
                            board_state[card.real_suit] += 1
                        potential += answer
                    if not worth_hinting[player] and rank is not info_rank:
                        potential *= already_has_play_multiplier
                    if debug and round_info.log:
                        self.info('{0} {1}'.format(rank, potential))
                    if potential > max_potential:
                        max_player_number = player
                        max_potential = potential
                        max_hint = rank

                board_state = deepcopy(predicted_board_state[utils.prev_player_number(round_info, player)])
                for suit in potential_playable_suits[player]:
                    potential = 0
                    current_rank = board_state[suit] + 1
                    for card in potential_playable_suits[player][suit]:
                        if suit is not info_suit:
                            answer = check_card_potential(card, player, board_state, current_rank)
                        else:
                            answer = check_card_potential(card, player, board_state, current_rank, pure_info=True)
                        potential += answer[0]
                        current_rank = answer[1]
                    if not worth_hinting[player] and suit is not info_suit:
                        potential *= already_has_play_multiplier
                    if debug and round_info.log:
                        self.info('{0} {1}'.format(suit, potential))
                    if potential > max_potential:
                        max_player_number = player
                        max_potential = potential
                        max_hint = suit

        if max_potential >= hint_pass_score:
            return ChoiceDetails(
                Choice.HINT,
                HintDetails(max_player_number, max_hint)
            )
        return False
Exemplo n.º 2
0
    def check_for_save_tip(self, round_info, player_number):
        best_player_number = -1
        best_play_priority = False
        best_hint_type = None
        best_hint_rank = 6

        remaining = utils.list_remaining_playable_cards(round_info)
        original_player_number = player_number
        player_number = utils.next_player_number(round_info, utils.next_player_number(round_info, player_number))

        while player_number is not original_player_number and not best_play_priority:
            player_hand = utils.get_player_hand_by_number(round_info, player_number)

            play_priority = False
            prev_player = utils.prev_player_number(round_info, player_number)
            play = self.check_for_obvious_play(round_info, prev_player)
            if play is False:
                play = self.check_for_hinted_play(round_info, prev_player)

            if play is not False:
                play_priority = True

            discarded_position = self.check_for_guess_discard(round_info, player_number)[1]
            discarded_card = player_hand[discarded_position]

            if remaining[discarded_card.real_suit][discarded_card.real_rank] == 1 and \
                    max(round_info.board_state.values()) < discarded_card.real_rank.value - 1 and \
                    discarded_card.revealed_rank is None and discarded_card.revealed_suit is None:
                best_player_number = player_number
                best_play_priority = play_priority
                best_hint_type = discarded_card.real_rank

            player_number = utils.next_player_number(round_info, player_number)

        if best_hint_type is None:
            player_number = utils.next_player_number(round_info, utils.next_player_number(round_info, player_number))

            while player_number is not original_player_number and not best_play_priority:
                player_hand = utils.get_player_hand_by_number(round_info, player_number)

                play_priority = False
                prev_player = utils.prev_player_number(round_info, player_number)
                if prev_player is not original_player_number:
                    play = self.check_for_obvious_play(round_info, prev_player)
                    if play is False:
                        play = self.check_for_hinted_play(round_info, prev_player)

                    if play is not False:
                        play_priority = True

                for card in player_hand:
                    if remaining[card.real_suit][card.real_rank] == 1 and \
                            max(round_info.board_state.values()) < card.real_rank.value - 1 and \
                            card.revealed_rank is None and card.revealed_suit is None and \
                            best_hint_rank > card.real_rank.value:
                        best_player_number = player_number
                        best_play_priority = play_priority
                        best_hint_type = card.real_rank
                        best_hint_rank = card.real_rank.value

                player_number = utils.next_player_number(round_info, player_number)

        if best_hint_type is not None:
            return ChoiceDetails(
                Choice.HINT,
                HintDetails(best_player_number, best_hint_type)
            )
        return False
    def update(self):
        if self.game.is_game_over():
            self.end_game_popup.show()
            return

        if self.game.player_turn == 0:
            if self.player_choice is None:
                return

            self.player_choice.tint()

            if self.game_buttons.play_toggle.state == 'down':
                choice = Choice.PLAY
            elif self.game_buttons.discard_toggle.state == 'down':
                choice = Choice.DISCARD
            else:
                choice = Choice.HINT

            if choice is Choice.PLAY or choice is Choice.DISCARD:
                self.last_card.update()
                self.player_choice = utils.ChoiceDetails(
                    choice, self.player_choice.hand_position)
            else:
                if self.game_buttons.hint_rank_toggle.state == 'down':
                    details = self.player_choice.real_rank
                else:
                    details = self.player_choice.real_suit

                self.player_choice = utils.ChoiceDetails(
                    Choice.HINT,
                    utils.HintDetails(self.player_choice.player_number,
                                      details))

            self.game.make_move()
            self.player_choice = None

        while self.game.is_game_over() is False:
            info_msg = self.game.make_move()
            self.players.update_player(
                utils.prev_player_number(self.game, self.game.player_turn) - 1,
                info_msg)

            if self.game.player_turn == 0:
                break

        if self.game.hints == 0:
            self.players.untint_all()
            self.players.set_untintable()
            self.player_choice = None

        self.game_info.update(self.game)
        self.players.update()
        self.human.update()
        self.board.update()

        if self.game.is_game_over():
            self.human.set_tintable()
            self.human.untint_all()
            self.human.set_untintable()
            self.human.reveal()
            self.players.set_tintable()
            self.players.untint_all()
            self.players.set_untintable()

            self.end_game_popup.show()