def get_tempura_value(game_knowledge, hand_estimation): hand = game_knowledge['currentHand'] plate = game_knowledge['currentPlate'] if YoniUtils.find_first_card_index(hand, Cards.Tempura) is None: return -1 num_of_cards = len(hand) num_of_players = len(game_knowledge['players']) my_index = game_knowledge['playerIndex'] tempuras_on_plate = YoniUtils.count_card_occurrences(plate, Cards.Tempura) future_tempuras = 0 for move_index in range(num_of_cards): current_holder_index = YoniUtils.normalize_index(my_index - move_index, num_of_players) estimated_tempuras_in_hand = hand_estimation[current_holder_index][Cards.Tempura] loop_index = math.floor(move_index / num_of_players) estimated_tempuras_in_hand -= loop_index remaining_cards_ratio = (num_of_cards - move_index) / num_of_cards estimated_tempuras_in_hand *= remaining_cards_ratio future_tempuras += min(1, max(0, estimated_tempuras_in_hand)) bonus = 0 if future_tempuras < 1.25: next_player_index = (my_index + 1) % num_of_players next_player_plate = game_knowledge['rounds'][-1]['plates'][next_player_index] tempuras_on_next_plate = YoniUtils.count_card_occurrences(next_player_plate, Cards.Tempura) if tempuras_on_next_plate % 2 == 1: bonus = 5 if int(tempuras_on_plate) % 2 == 1: return 5 + bonus return min(1, (future_tempuras-1) / 1.5) * 2.5 + bonus
def get_maki_value(game_knowledge, hand_estimations): hand = game_knowledge['currentHand'] plate = game_knowledge['currentPlate'] num_of_players = len(game_knowledge['players']) if YoniUtils.find_first_card_index(hand, Cards.Maki1) is None and \ YoniUtils.find_first_card_index(hand, Cards.Maki2) is None and \ YoniUtils.find_first_card_index(hand, Cards.Maki3) is None: return -1 strongest_maki = get_strongest_maki(hand) total_maki = 0 for player_index in range(num_of_players): hand_estimation = hand_estimations[player_index] total_maki += hand_estimation[Cards.Maki1] total_maki += hand_estimation[Cards.Maki2] * 2 total_maki += hand_estimation[Cards.Maki3] * 3 makis_on_plates = [ count_makis_on_plate(plate) for plate in game_knowledge['rounds'][-1]['plates'] ] makis_required_to_win = calc_makis_required_to_win( makis_on_plates, total_maki, game_knowledge['playerIndex']) missing_makis = makis_required_to_win - makis_on_plates[ game_knowledge['playerIndex']] if missing_makis <= 0: return 0 potential_step_ratio1 = min(1.0, strongest_maki / missing_makis) potential_step_ratio2 = min(1.0, strongest_maki / total_maki) return (potential_step_ratio1 * 0.5 + potential_step_ratio2 * 0.5) * 4.5
def get_strongest_nigiri(hand): nigiri3_count = YoniUtils.count_card_occurrences(hand, Cards.Nigiri3) nigiri2_count = YoniUtils.count_card_occurrences(hand, Cards.Nigiri2) nigiri1_count = YoniUtils.count_card_occurrences(hand, Cards.Nigiri1) if nigiri3_count > 0: return 3 if nigiri2_count > 0: return 2 if nigiri1_count > 0: return 1 return 0
def get_strongest_maki(hand): maki3_count = YoniUtils.count_card_occurrences(hand, Cards.Maki3) maki2_count = YoniUtils.count_card_occurrences(hand, Cards.Maki2) maki1_count = YoniUtils.count_card_occurrences(hand, Cards.Maki1) if maki3_count > 0: return 3 if maki2_count > 0: return 2 if maki1_count > 0: return 1 return 0
def get_dumpling_value(game_knowledge, hand_estimation): hand = game_knowledge['currentHand'] plate = game_knowledge['currentPlate'] if YoniUtils.find_first_card_index(hand, Cards.Dumpling) is None: return -1 num_of_cards = len(hand) num_of_players = len(game_knowledge['players']) my_index = game_knowledge['playerIndex'] dumplings_on_plate = YoniUtils.count_card_occurrences( plate, Cards.Dumpling) future_dumplings = 0 for move_index in range(num_of_cards): current_holder_index = YoniUtils.normalize_index( my_index - move_index, num_of_players) estimated_dumplings_in_hand = hand_estimation[current_holder_index][ Cards.Dumpling] loop_index = math.floor(move_index / num_of_players) estimated_dumplings_in_hand -= loop_index remaining_cards_ratio = (num_of_cards - move_index) / num_of_cards estimated_dumplings_in_hand *= remaining_cards_ratio future_dumplings += min(1, max(0, estimated_dumplings_in_hand)) bonus = 0 if future_dumplings < 1.25: next_player_index = (my_index + 1) % num_of_players next_player_plate = game_knowledge['rounds'][-1]['plates'][ next_player_index] dumplings_on_next_plate = YoniUtils.count_card_occurrences( next_player_plate, Cards.Dumpling) if dumplings_on_next_plate >= 2: bonus = 3 current_dumpling_score = 0 for i in range(dumplings_on_plate): current_dumpling_score += i + 1 next_dumpling_score = dumplings_on_plate + 1 dumpling_count = 0 future_dumpling_score = 0 while dumpling_count + 1 <= future_dumplings: future_dumpling_score += next_dumpling_score next_dumpling_score += 1 dumpling_count += 1 remainder = future_dumplings - dumpling_count future_dumpling_score += remainder * (dumpling_count + 1) card_value = future_dumpling_score / future_dumplings return card_value + bonus
def get_nigiri_value(game_knowledge, hand_estimation): hand = game_knowledge['currentHand'] plate = game_knowledge['currentPlate'] if YoniUtils.find_first_card_index(hand, Cards.Nigiri1) is None and \ YoniUtils.find_first_card_index(hand, Cards.Nigiri2) is None and \ YoniUtils.find_first_card_index(hand, Cards.Nigiri3) is None: return -1 strongest_nigiri = get_strongest_nigiri(hand) has_wasabi = has_wasabi_waiting(plate) if has_wasabi: strongest_nigiri *= 3 return strongest_nigiri
def get_wasabi_value(game_knowledge, hand_estimation): hand = game_knowledge['currentHand'] plate = game_knowledge['currentPlate'] if YoniUtils.find_first_card_index(hand, Cards.Wasabi) is None: return -1 num_of_cards = len(hand) num_of_players = len(game_knowledge['players']) my_index = game_knowledge['playerIndex'] waiting_wasabis_on_plate = count_waiting_wasabis(plate) future_nigiri1 = 0 for move_index in range(1, num_of_cards): current_holder_index = YoniUtils.normalize_index(my_index - move_index, num_of_players) estimated_nigiri1_in_hand = hand_estimation[current_holder_index][Cards.Nigiri1] loop_index = math.floor((move_index - 1) / num_of_players) estimated_nigiri1_in_hand -= loop_index remaining_cards_ratio = (num_of_cards - move_index) / num_of_cards estimated_nigiri1_in_hand *= remaining_cards_ratio future_nigiri1 += min(1, max(0, estimated_nigiri1_in_hand)) future_nigiri2 = 0 for move_index in range(1, num_of_cards): current_holder_index = YoniUtils.normalize_index(my_index - move_index, num_of_players) estimated_nigiri2_in_hand = hand_estimation[current_holder_index][Cards.Nigiri2] loop_index = math.floor((move_index - 1) / num_of_players) estimated_nigiri2_in_hand -= loop_index remaining_cards_ratio = (num_of_cards - move_index) / num_of_cards estimated_nigiri2_in_hand *= remaining_cards_ratio future_nigiri2 += min(1, max(0, estimated_nigiri2_in_hand)) future_nigiri3 = 0 for move_index in range(1, num_of_cards): current_holder_index = YoniUtils.normalize_index(my_index - move_index, num_of_players) estimated_nigiri3_in_hand = hand_estimation[current_holder_index][Cards.Nigiri3] loop_index = math.floor((move_index - 1) / num_of_players) estimated_nigiri3_in_hand -= loop_index remaining_cards_ratio = (num_of_cards - move_index) / num_of_cards estimated_nigiri3_in_hand *= remaining_cards_ratio future_nigiri3 += min(1, max(0, estimated_nigiri3_in_hand)) future_nigiri = future_nigiri1 + (2*future_nigiri2) + (3*future_nigiri3) future_nigiri /= (waiting_wasabis_on_plate + 1) return min(1, future_nigiri / 6) * 4.5
def get_hands_memory(game_knowledge): num_of_players = len(game_knowledge['players']) my_index = game_knowledge['playerIndex'] hands = [None for _ in range(num_of_players)] current_round = game_knowledge['rounds'][-1] for move in current_round['roundMoves']: hands[my_index] = YoniUtils.copy_list(move['hand']) chosen_cards = move['chosenCards'] for player_index in range(len(chosen_cards)): player_chosen_cards = chosen_cards[player_index] if hands[player_index] is not None: for chosen_card in player_chosen_cards: index_of_card_to_delete = YoniUtils.find_first_card_index( hands[player_index], chosen_card) del hands[player_index][index_of_card_to_delete] if len(player_chosen_cards) > 1: hands[player_index].append(Cards.Chopsticks) hands = rotate_hands(hands) hands[my_index] = YoniUtils.copy_list(game_knowledge['currentHand']) return hands
def estimate_hands(game_knowledge, hands_memory): current_hand = game_knowledge['currentHand'] num_of_cards = len(current_hand) num_of_players = len(game_knowledge['players']) hand_estimations = [] remaining_card_quantities = {} for card in card_quantities: remaining_card_quantities[card] = card_quantities[card] for round in game_knowledge['rounds']: for plate in round['plates']: for card in plate: remaining_card_quantities[card] -= 1 for hand in hands_memory: if hand is not None: for card in hand: remaining_card_quantities[card] -= 1 total_remaining_cards = sum([ remaining_card_quantities[card] for card in remaining_card_quantities ]) for player_index in range(num_of_players): if hands_memory[player_index] is not None: hand_estimation = {} for card in card_quantities: hand_estimation[card] = YoniUtils.count_card_occurrences( hands_memory[player_index], card) hand_estimations.append(hand_estimation) continue hand_estimation = {} if player_index == game_knowledge['playerIndex']: for card in card_quantities: hand_estimation[card] = YoniUtils.count_card_occurrences( current_hand, card) else: for card in card_quantities: hand_estimation[card] = (num_of_cards / total_remaining_cards ) * remaining_card_quantities[card] hand_estimations.append(hand_estimation) return hand_estimations
def get_pudding_value(game_knowledge, hand_estimations): hand = game_knowledge['currentHand'] if YoniUtils.find_first_card_index(hand, Cards.Pudding) is None: return -1 pudding_counts = get_current_pudding_counts(game_knowledge) remaining_puddings = calc_remaining_puddings(game_knowledge, pudding_counts, hand_estimations) puddings_required_to_win = calc_puddings_required_to_win(pudding_counts, remaining_puddings, game_knowledge['playerIndex']) missing_puddings = puddings_required_to_win - pudding_counts[game_knowledge['playerIndex']] if missing_puddings <= 0: return 0 potential_step_ratio1 = min(1.0, 1 / missing_puddings) potential_step_ratio2 = min(1.0, 1 / remaining_puddings) return (potential_step_ratio1*0.5 + potential_step_ratio2*0.5) * 10
def count_puddings_on_plate(plate): return YoniUtils.count_card_occurrences(plate, Cards.Pudding)
def get_index_of_best_card(hand, best_card_type): possible_cards = type_to_possible_cards[best_card_type] for possible_card in possible_cards: card_index = YoniUtils.find_first_card_index(hand, possible_card) if card_index is not None: return card_index
def get_chopsticks_value(game_knowledge): hand = game_knowledge['currentHand'] if YoniUtils.find_first_card_index(hand, Cards.Chopsticks) is None: return -1 return -0.1