import itertools from math import ceil from typing import Any, Iterator, TypeAlias from ..base import BaseSolver Modifier: TypeAlias = tuple[str, int, int, int] WEAPONS: list[Modifier] = [ ("Dagger", 8, 4, 0), ("Shortsword", 10, 5, 0), ("Warhammer", 25, 6, 0), ("Longsword", 40, 7, 0), ("Greataxe", 74, 8, 0), ] ARMORS: list[Modifier] = [ ("", 0, 0, 0), ("Leather", 13, 0, 1), ("Chainmail", 31, 0, 2), ("Splintmail", 53, 0, 3), ("Bandedmail", 75, 0, 4), ("Platemail", 102, 0, 5), ] RINGS: list[Modifier] = [ ("", 0, 0, 0), ("Damage +1", 25, 1, 0), ("Damage +2", 50, 2, 0), ("Damage +3", 100, 3, 0), ("Defense +1", 20, 0, 1), ("Defense +2", 40, 0, 2), ("Defense +3", 80, 0, 3), ] class Solver(BaseSolver): def solve(self, input: str) -> Iterator[Any]: lines = input.splitlines() player_hp = 100 boss_attack = int(lines[1].split(":")[1].strip()) boss_armor = int(lines[2].split(":")[1].strip()) boss_hp = int(lines[0].split(":")[1].strip()) min_cost, max_cost = 1_000_000, 0 for equipments in itertools.product(WEAPONS, ARMORS, RINGS, RINGS): if equipments[-1][0] != "" and equipments[-2] == equipments[-1]: continue cost, player_attack, player_armor = ( sum(equipment[1:][k] for equipment in equipments) for k in range(3) ) if ceil(boss_hp / max(1, player_attack - boss_armor)) <= ceil( player_hp / max(1, boss_attack - player_armor) ): min_cost = min(cost, min_cost) else: max_cost = max(cost, max_cost) yield min_cost yield max_cost