#!/usr/bin/env python from itertools import product from collections import namedtuple from math import ceil Item = namedtuple('Item', ['cost', 'damage', 'armor']) Character = namedtuple('Character', ['hp', 'damage', 'armor']) weapons = [ Item(8, 4, 0), Item(10, 5, 0), Item(25, 6, 0), Item(40, 7, 0), Item(74, 8, 0) ] armor = [ Item(0, 0, 0), Item(13, 0, 1), Item(31, 0, 2), Item(53, 0, 3), Item(75, 0, 4), Item(102, 0, 5) ] rings = [ Item(25, 1, 0), Item(50, 2, 0), Item(100, 3, 0), Item(20, 0, 1), Item(40, 0, 2), Item(80, 0, 3), Item(0, 0, 0), Item(0, 0, 0) ] def willWin(player, boss): playerMoves = ceil(player.hp / max(boss.damage - player.armor, 1)) bossMoves = ceil(boss.hp / max(player.damage - boss.armor, 1)) return playerMoves >= bossMoves boss = Character(103, 9, 2) winningCosts = [] losingCosts = [] for weapon, shield, ring1, ring2 in product(weapons, armor, rings, rings): if ring1.cost == ring2.cost and ring1.cost != 0: continue totalCost = weapon.cost + shield.cost + ring1.cost + ring2.cost totalDamage = weapon.damage + shield.damage + ring1.damage + ring2.damage totalArmor = weapon.armor + shield.armor + ring1.armor + ring2.armor player = Character(100, totalDamage, totalArmor) if willWin(player, boss): winningCosts.append(totalCost) else: losingCosts.append(totalCost) # part 1 print(min(winningCosts)) # part 2 print(max(losingCosts))