/ Python / 2015 / 21.py
21.py
 1  from lib import *
 2  
 3  input = read_input(2015, 21)
 4  
 5  (*_, boss_hp), (*_, boss_damage), (*_, boss_armor) = map(str.split, input.splitlines())
 6  
 7  boss_hp, boss_damage, boss_armor = map(int, [boss_hp, boss_damage, boss_armor])
 8  
 9  
10  player_hp = 100
11  
12  
13  NEUTRAL = (0, 0, 0)
14  shop_weapons = [(8, 4, 0), (10, 5, 0), (25, 6, 0), (40, 7, 0), (74, 8, 0)]
15  shop_armor = [NEUTRAL, (13, 0, 1), (31, 0, 2), (53, 0, 3), (75, 0, 4), (102, 0, 5)]
16  shop_rings = [NEUTRAL, NEUTRAL, (25, 1, 0), (50, 2, 0), (100, 3, 0), (20, 0, 1), (40, 0, 2), (80, 0, 3)]
17  
18  
19  def fight(player_damage, player_armor):
20      player = player_hp
21      boss = boss_hp
22      while True:
23          boss -= max(1, player_damage - boss_armor)
24          if boss <= 0:
25              return True
26          player -= max(1, boss_damage - player_armor)
27          if player <= 0:
28              return False
29  
30  
31  def combine(*args):
32      return tuple(map(sum, zip(*args)))
33  
34  
35  best = 1e1337
36  for weapon in shop_weapons:
37      for armor in shop_armor:
38          for i, ring1 in enumerate(shop_rings):
39              for ring2 in shop_rings[i + 1 :]:
40                  cost, d, a = combine(weapon, armor, ring1, ring2)
41                  if fight(d, a):
42                      best = min(best, cost)
43  print(best)
44  
45  
46  best = 0
47  for weapon in shop_weapons:
48      for armor in shop_armor:
49          for i, ring1 in enumerate(shop_rings):
50              for ring2 in shop_rings[i + 1 :]:
51                  cost, d, a = combine(weapon, armor, ring1, ring2)
52                  if not fight(d, a):
53                      best = max(best, cost)
54  print(best)