Advertisement
Guest User

Untitled

a guest
Dec 7th, 2023
260
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.61 KB | None | 0 0
  1. from collections import Counter
  2. from functools import cmp_to_key
  3.  
  4. def main():
  5.   with open("input.txt") as file:
  6.     lines = [line.rstrip() for line in file]
  7.     part_1(lines)
  8.     part_2(lines)
  9.  
  10. def part_1(lines):
  11.   hands_and_bids = parse_input(lines, 1)
  12.   hab_by_rank = rank_hands_and_bids(hands_and_bids, 1)
  13.   total_winnings = calculate_total_winnings(hab_by_rank)
  14.   print(total_winnings)
  15.  
  16. def part_2(lines):
  17.   hands_and_bids = parse_input(lines, 2)
  18.   hab_by_rank = rank_hands_and_bids(hands_and_bids, 2)
  19.   total_winnings = calculate_total_winnings(hab_by_rank)
  20.   print(total_winnings)
  21.  
  22. def parse_input(lines, part):
  23.   hands_and_bids = [(hand, int(bid)) for hand, bid in (line.split() for line in lines)]
  24.   frequencies = [
  25.     {"counts": Counter(hand), "hand": hand, "bid": bid}
  26.     for hand, bid in hands_and_bids
  27.   ]
  28.   if part == 1:
  29.     return frequencies
  30.   if part == 2:
  31.     return convert_jokers(frequencies)
  32.  
  33. def convert_jokers(frequencies):
  34.   for f in frequencies:
  35.     counter = f["counts"]
  36.     if counter["J"] == 5:
  37.       continue
  38.  
  39.     num_jokers = counter.pop("J", 0)
  40.     most_common_card, _ = f["counts"].most_common(1)[0]
  41.     counter[most_common_card] += num_jokers
  42.   return frequencies
  43.  
  44. def rank_hands_and_bids(frequencies, part):
  45.   return sorted(frequencies, key=cmp_to_key(lambda f1, f2: compare_hands(f1, f2, part)), reverse=True)
  46.  
  47. def calculate_total_winnings(sorted_values):
  48.   sum = 0
  49.   for i, item in enumerate(sorted_values):
  50.     sum += item["bid"] * (i + 1)
  51.   return sum
  52.  
  53. def compare_hands(f1, f2, part):
  54.   counts1, counts2 = f1["counts"], f2["counts"]
  55.   if len(counts1) < len(counts2):
  56.     return -1
  57.   elif len(counts2) < len(counts1):
  58.     return 1
  59.  
  60.   # same length, check custom rules
  61.   values1, values2 = counts1.values(), counts2.values()
  62.   if len(counts1) == 2:
  63.     # possible hands: 4-of-a-kind, or full house
  64.     if 4 in values1 and 4 not in values2:
  65.       return -1
  66.     elif 4 not in values1 and 4 in values2:
  67.       return 1
  68.  
  69.   if len(counts1) == 3:
  70.     # possible hands: 3-of-a-kind, or 2 pairs
  71.     if 3 in values1 and 3 not in values2:
  72.       return -1
  73.     elif 3 not in values1 and 3 in values2:
  74.       return 1
  75.    
  76.   return compare_same_type_of_hands(f1, f2, part)
  77.  
  78. def compare_same_type_of_hands(f1, f2, part):
  79.   chars = zip(f1["hand"], f2["hand"])
  80.   ordering = "AKQJT98765432" if part == 1 else "AKQT98765432J"
  81.   for l, r in chars:
  82.     l_index, r_index = ordering.index(l), ordering.index(r)
  83.     if l_index < r_index:
  84.       return -1
  85.     elif r_index < l_index:
  86.       return 1
  87.   print("same idx??")
  88.   return 0
  89.  
  90. if __name__ == "__main__":
  91.   main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement