Advertisement
CrayonCrayoff

AoC 2015 Day 21

Dec 8th, 2024 (edited)
48
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.06 KB | Source Code | 0 0
  1. import re
  2. from itertools import combinations
  3.  
  4. with open("testinput.txt") as f:
  5.     input_lines = f.read().splitlines()
  6.  
  7. input_len = len(input_lines)
  8.  
  9. idx = 1
  10.  
  11. # find all weapons
  12. input_weapons = []
  13. for i in range(idx, input_len):
  14.     if input_lines[i] == '':
  15.         idx = i + 2
  16.         break
  17.     else:
  18.         input_weapons.append([int(x) for x in re.findall("\d+", input_lines[i])])
  19.  
  20. # find all armors
  21. # list starts off with [0, 0, 0], representing not picking armor
  22. input_armors = [[0, 0, 0]]
  23. for i in range(idx, input_len):
  24.     if input_lines[i] == '':
  25.         idx = i + 2
  26.         break
  27.     else:
  28.         input_armors.append([int(x) for x in re.findall("\d+", input_lines[i])])
  29.  
  30. # find all cost, damage and armor values of the rings.
  31. # [0, 0, 0] represents not picking a ring
  32. input_rings = [[0, 0, 0], [0, 0, 0]]
  33. for i in range(idx, input_len):
  34.     if input_lines[i] == '':
  35.         idx = i + 2
  36.         break
  37.     else:
  38.         input_rings.append([int(x) for x in re.findall("\d+", input_lines[i])[1:]])
  39. # find every combination of two picks in the rings list.
  40. # this is why it starts off with two [0, 0, 0]. One possible combination is not picking a ring at all.
  41. input_rings = list(combinations(input_rings, 2))
  42.  
  43.  
  44. # helper function to see who wins with the selected loadout
  45. def check_victory(player_dmg: int, player_arm: int) -> bool:
  46.     player_hp = 100
  47.     boss_hp, boss_dmg, boss_arm = 100, 8, 2
  48.  
  49.     while player_hp > 0:
  50.         boss_hp -= player_dmg - boss_arm
  51.         if boss_hp <= 0:
  52.             break
  53.         boss_hit = boss_dmg - player_arm
  54.         if boss_hit <= 0:
  55.             player_hp -= 1
  56.         else:
  57.             player_hp -= boss_hit
  58.  
  59.     return player_hp > 0
  60.  
  61.  
  62. def cheapest_loadout(weapons: list[list[int]], armors: list[list[int]], rings: list[tuple[list[int]]]):
  63.     output = float('inf')
  64.     # iterate through every possible loadout. Use check_victory to see if it wins
  65.     # if it does and the total_cost is lower than the current output, update output
  66.     for weapon in weapons:
  67.         for armor in armors:
  68.             for ring in rings:
  69.                 total_cost = weapon[0] + armor[0] + ring[0][0] + ring[1][0]
  70.                 if check_victory(weapon[1] + ring[0][1] + ring[1][1], armor[2] + ring[0][2] + ring[1][2]):
  71.                     output = min(output, total_cost)
  72.     return output
  73.  
  74.  
  75. print(cheapest_loadout(input_weapons, input_armors, input_rings))
  76.  
  77.  
  78. # we do the same thing as in cheapest_loadout(), but instead we check for losses and maximize output
  79. def most_expensive_loadout(weapons: list[list[int]], armors: list[list[int]], rings: list[tuple[list[int]]]):
  80.     output = float('-inf')
  81.     for weapon in weapons:
  82.         for armor in armors:
  83.             for ring in rings:
  84.                 total_cost = weapon[0] + armor[0] + ring[0][0] + ring[1][0]
  85.                 if not check_victory(weapon[1] + ring[0][1] + ring[1][1], armor[2] + ring[0][2] + ring[1][2]):
  86.                     output = max(output, total_cost)
  87.  
  88.     return output
  89.  
  90.  
  91. print(most_expensive_loadout(input_weapons, input_armors, input_rings))
  92.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement