from math import ceil from dataclasses import dataclass @dataclass class Item: cost: int damage: int armour: int weapons = [ Item(8, 4, 0), Item(10, 5, 0), Item(25, 6, 0), Item(40, 7, 0), Item(74, 8, 0), ] armour = [ 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(0, 0, 0), Item(25, 1, 0), Item(50, 2, 0), Item(100, 3, 0), Item(20, 0, 1), Item(40, 0, 2), Item(80, 0, 3), ] @dataclass class Player: hit_points: int damage: int armour: int def damage_dealt(by: Player, to: Player) -> int: return max(1, by.damage - to.armour) def part1(opponent: Player) -> int: min_cost = float('inf') for weapon in weapons: for a in armour: for ring1 in rings: for ring2 in rings: if ring1 == ring2: continue player = Player(100, weapon.damage + ring1.damage + ring2.damage, a.armour + ring1.armour + ring2.armour) pturns = ceil(opponent.hit_points / damage_dealt(by=player, to=opponent)) oturns = ceil(player.hit_points / damage_dealt(by=opponent, to=player)) if pturns <= oturns: min_cost = min(min_cost, weapon.cost + a.cost + ring1.cost + ring2.cost) return min_cost def part2(opponent: Player) -> int: max_cost = 0 for weapon in weapons: for a in armour: for ring1 in rings: for ring2 in rings: if ring1 == ring2: continue player = Player(100, weapon.damage + ring1.damage + ring2.damage, a.armour + ring1.armour + ring2.armour) pturns = ceil(opponent.hit_points / damage_dealt(by=player, to=opponent)) oturns = ceil(player.hit_points / damage_dealt(by=opponent, to=player)) if pturns > oturns: max_cost = max(max_cost, weapon.cost + a.cost + ring1.cost + ring2.cost) return max_cost if __name__ == '__main__': opponent = Player(103, 9, 2) print(part1(opponent)) print(part2(opponent))