def check_for_forced_discard(self, round_info, player_number): if player_number is round_info.player_turn: player_hand = round_info.true_hand_info() else: player_hand = utils.get_player_hand_by_number( round_info, player_number) known = self.list_all_known_cards(round_info, player_number) remaining = utils.list_remaining_playable_cards(round_info) for card in player_hand: if known[card.real_suit][card.real_rank] > 1: return ChoiceDetails(Choice.DISCARD, card.hand_position) for card in player_hand: if remaining[card.real_suit][card.real_rank] > 1: return ChoiceDetails(Choice.DISCARD, card.hand_position) best_card_rank = -1 best_card = None for card in player_hand: if card.real_rank.value > best_card_rank: best_card = card.hand_position best_card_rank = card.real_rank.value return ChoiceDetails(Choice.DISCARD, best_card)
def initialize_variables(self, round_info): self.remaining = utils.list_remaining_playable_cards(round_info) self.point_of_uselessness = {} for suit in utils.Suit: self.point_of_uselessness[suit] = None for rank in utils.Rank: if round_info.board_state[suit] < rank.value: if self.point_of_uselessness[suit] is None and self.remaining[suit][rank] == 0: self.point_of_uselessness[suit] = rank original_player_number = round_info.player_turn player_number = utils.next_player_number(round_info, original_player_number) oldest_age = -1 for card in round_info.player_hand: card_age = round_info.current_turn - card.drawn_on_turn if card_age > oldest_age: oldest_age = card_age self.oldest_card[original_player_number] = card.hand_position while player_number is not original_player_number: player_hand = utils.get_player_hand_by_number(round_info, player_number) oldest_age = -1 for card in player_hand: card_age = round_info.current_turn - card.drawn_on_turn if card_age > oldest_age: oldest_age = card_age self.oldest_card[player_number] = card.hand_position player_number = utils.next_player_number(round_info, player_number)
def check_for_guess_discard(self, round_info, player_number): if player_number is round_info.player_turn: player_hand = round_info.player_hand else: player_hand = utils.get_player_hand_by_number(round_info, player_number) unmarked = [] for card in player_hand: if card.revealed_rank is None and card.revealed_suit is None: unmarked.append(card) if len(unmarked) == 0: known = utils.list_all_known_cards(round_info, player_number)[0] remaining = utils.list_remaining_playable_cards(round_info) discarded = utils.list_discarded_cards(round_info) for card in player_hand: if card.revealed_rank is None: add = True for rank in utils.Rank: if round_info.board_state[card.revealed_suit] < rank.value and \ remaining[card.revealed_suit][rank] == 1 and \ known[card.revealed_suit][rank] - discarded[card.revealed_suit][rank] == 0: add = False if add: unmarked.append(card) elif card.revealed_suit is None: add = True for suit in remaining: if round_info.board_state[suit] < card.revealed_rank.value and \ remaining[suit][card.revealed_rank] == 1 and \ known[suit][card.revealed_rank] - discarded[suit][card.revealed_rank] == 0: add = False if add: unmarked.append(card) if len(unmarked) == 0: unmarked = player_hand oldest = unmarked[0] for card in unmarked: if card.drawn_on_turn < oldest.drawn_on_turn: oldest = card return ChoiceDetails( Choice.DISCARD, oldest.hand_position )
def check_for_obvious_discard(self, round_info, player_number): if player_number is round_info.player_turn: player_hand = round_info.player_hand else: player_hand = utils.get_player_hand_by_number(round_info, player_number) known = utils.list_all_known_cards(round_info)[0] discarded = utils.list_discarded_cards(round_info) remaining = utils.list_remaining_playable_cards(round_info) for card in player_hand: useless = False if card.revealed_suit is not None: useless = True future_ranks_useless = False for rank in utils.Rank: if round_info.board_state[card.revealed_suit] < rank.value: if not future_ranks_useless and remaining[card.revealed_suit][rank] - \ known[card.revealed_suit][rank] + discarded[card.revealed_suit][rank] > 0: useless = False else: future_ranks_useless = True if card.revealed_rank is not None: useless = True for suit in utils.Suit: if round_info.board_state[suit] < card.revealed_rank.value: if remaining[suit][card.revealed_rank] - known[suit][card.revealed_rank] + \ discarded[suit][card.revealed_rank] > 0: useless = False if card.revealed_suit is not None and card.revealed_rank is not None: if round_info.board_state[card.revealed_suit] >= card.revealed_rank.value: useless = True if useless: return ChoiceDetails( Choice.DISCARD, card.hand_position ) return False
def check_card_usefulness(self, round_info, card): remaining = utils.list_remaining_playable_cards(round_info) useless = False point_of_uselessness = {} for suit in utils.Suit: point_of_uselessness[suit] = None for rank in utils.Rank: if round_info.board_state[suit] < rank.value: if point_of_uselessness[suit] is None and remaining[suit][rank] == 0: point_of_uselessness[suit] = rank if card.revealed_suit is not None: if round_info.board_state[card.revealed_suit] == 5 or \ (point_of_uselessness[card.revealed_suit] is not None and round_info.board_state[card.revealed_suit] + 1 is point_of_uselessness[card.revealed_suit].value): useless = True if card.revealed_rank is not None: useless = True for suit in utils.Suit: if round_info.board_state[suit] < card.revealed_rank.value and \ (point_of_uselessness[suit] is None or point_of_uselessness[suit].value > card.revealed_rank.value): useless = False if card.revealed_suit is not None and card.revealed_rank is not None: if round_info.board_state[card.revealed_suit] < card.revealed_rank.value and \ (point_of_uselessness[card.revealed_suit] is None or point_of_uselessness[card.revealed_suit].value > card.revealed_rank.value): useless = False else: useless = True if useless: return ChoiceDetails( Choice.DISCARD, card.hand_position ) return False
def check_for_necessary_tip(self, round_info, player_number): if round_info.hints == 0: return False remaining = utils.list_remaining_playable_cards(round_info) next_player_hand = utils.next_player_hand(round_info, player_number) next_player_number = utils.next_player_number(round_info, player_number) discarded_position = self.check_for_guess_discard(round_info, next_player_number)[1] discarded = next_player_hand[discarded_position] if round_info.board_state[discarded.real_suit] < discarded.real_rank.value and \ remaining[discarded.real_suit][discarded.real_rank] == 1 and \ discarded.real_rank.value - round_info.board_state[discarded.real_suit] <= 1: if discarded.revealed_rank is None: return ChoiceDetails( Choice.HINT, HintDetails(utils.next_player_number(round_info, player_number), discarded.real_rank) ) else: return ChoiceDetails( Choice.HINT, HintDetails(utils.next_player_number(round_info, player_number), discarded.real_suit) ) 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 check_for_necessary_tip(self, round_info, player_number): if round_info.hints == 0 or round_info.hints == utils.MAX_HINTS: return False if player_number is round_info.player_turn: player_hand = round_info.player_hand else: player_hand = utils.get_player_hand_by_number(round_info, player_number) remaining = utils.list_remaining_playable_cards(round_info) next_player_hand = utils.next_player_hand(round_info, player_number) next_player_number = utils.next_player_number(round_info, player_number) if self.check_for_obvious_play(round_info, next_player_number) is not False: return False distrust = False play = self.check_for_hinted_play(round_info, next_player_number) if play is not False: play_position = play[1] played_card = next_player_hand[play_position] if round_info.board_state[played_card.real_suit] is not played_card.real_rank.value - 1: distrust = True own_play = None if self.check_for_obvious_play(round_info, player_number) is not False: own_play = self.check_for_obvious_play(round_info, player_number)[1] if own_play is None and self.check_for_hinted_play(round_info, player_number) is not False: own_play = self.check_for_hinted_play(round_info, player_number)[1] if own_play is not None and \ round_info.board_state[played_card.real_suit] is played_card.real_rank.value - 2: own_card = player_hand[own_play] if (own_card.revealed_rank is not None and own_card.revealed_rank.value is played_card.real_rank.value - 1) or \ (own_card.revealed_suit is not None and own_card.revealed_suit is played_card.real_suit): distrust = False else: if self.check_for_obvious_discard(round_info, next_player_number) is False: played_position = self.check_for_guess_discard(round_info, next_player_number)[1] played_card = next_player_hand[played_position] if round_info.board_state[played_card.real_suit] < played_card.real_rank.value and \ remaining[played_card.real_suit][played_card.real_rank] == 1 and \ self.check_card_usefulness(round_info, played_card) is False: distrust = True if distrust: if debug and round_info.log: self.info("good_tip:") answer = self.check_for_good_tip(round_info, player_number, only_next_player=True) if answer is False: if debug and round_info.log: self.info("risky_tip:") answer = self.check_for_risky_tip(round_info, player_number, only_next_player=True) if answer is not False: return answer if played_card.revealed_rank is None: return ChoiceDetails( Choice.HINT, HintDetails(utils.next_player_number(round_info, player_number), played_card.real_rank) ) else: return ChoiceDetails( Choice.HINT, HintDetails(utils.next_player_number(round_info, player_number), played_card.real_suit) ) return False
def check_for_hinted_play(self, round_info, player_number): if player_number is round_info.player_turn: player_hand = round_info.player_hand else: player_hand = utils.get_player_hand_by_number(round_info, player_number) alignment_delta = 2 max_hint_size = 10 if round_info.lives == 1: alignment_delta = 0 max_hint_size = 1 hinted_ranks = {} hinted_suits = {} for suit in utils.Suit: hinted_suits[suit] = 0 for rank in utils.Rank: hinted_ranks[rank] = 0 for x in range(0, len(player_hand)): if player_hand[x].revealed_suit is not None and player_hand[x].revealed_rank is None and \ self.card_hint_type[player_number][x] == "Play": hinted_suits[player_hand[x].revealed_suit] += 1 if player_hand[x].revealed_rank is not None and player_hand[x].revealed_suit is None and \ self.card_hint_type[player_number][x] == "Play": hinted_ranks[player_hand[x].revealed_rank] += 1 known = utils.list_all_known_cards(round_info, player_number)[0] remaining = utils.list_remaining_playable_cards(round_info) discarded = utils.list_discarded_cards(round_info) best_hint = -1 best_hint_size = max_hint_size best_alignment = 0 hint_type = None for suit in hinted_suits: if 0 < hinted_suits[suit] <= best_hint_size: rank = round_info.board_state[suit] + 1 if rank <= 5: rank_rank = utils.Rank(rank) if remaining[suit][rank_rank] - known[suit][rank_rank] + discarded[suit][rank_rank] > 0: best_hint = suit best_hint_size = hinted_suits[suit] best_alignment = 1 hint_type = 'suit' board_alignment = {} for rank in utils.Rank: board_alignment[rank] = 0 for suit in round_info.board_state: rank = round_info.board_state[suit] + 1 if rank <= 5: rank_rank = utils.Rank(rank) if remaining[suit][rank_rank] - known[suit][rank_rank] + discarded[suit][rank_rank] > 0: board_alignment[rank_rank] += 1 for rank in hinted_ranks: if 0 < board_alignment[rank] and ((0 < hinted_ranks[rank] < best_hint_size) or (0 < hinted_ranks[rank] <= best_hint_size and best_alignment < board_alignment[rank])): best_hint = rank best_hint_size = hinted_ranks[rank] best_alignment = board_alignment[rank] hint_type = 'rank' if best_hint != -1 and best_hint_size <= best_alignment + alignment_delta: for x in range(0, len(player_hand)): if hint_type == 'rank': if player_hand[x].revealed_rank is not None and player_hand[x].revealed_suit is None and \ player_hand[x].revealed_rank is best_hint and \ self.card_hint_type[player_number][x] == "Play": return ChoiceDetails( Choice.PLAY, x ) else: if player_hand[x].revealed_suit is not None and player_hand[x].revealed_rank is None and \ player_hand[x].revealed_suit is best_hint and \ self.card_hint_type[player_number][x] == "Play": return ChoiceDetails( Choice.PLAY, x ) return False