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
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()