2015 day 22, part 1.
This commit is contained in:
parent
850c66cd8d
commit
dd8458fa96
168
src/holt59/aoc/2015/day22.py
Normal file
168
src/holt59/aoc/2015/day22.py
Normal file
@ -0,0 +1,168 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import heapq
|
||||
import sys
|
||||
from typing import Literal, TypeAlias
|
||||
|
||||
PlayerType: TypeAlias = Literal["player", "boss"]
|
||||
SpellType: TypeAlias = Literal["magic missile", "drain", "shield", "poison", "recharge"]
|
||||
BuffType: TypeAlias = Literal["shield", "poison", "recharge"]
|
||||
Node: TypeAlias = tuple[
|
||||
PlayerType,
|
||||
int,
|
||||
int,
|
||||
int,
|
||||
int,
|
||||
int,
|
||||
tuple[tuple[BuffType, int], ...],
|
||||
tuple[tuple[SpellType, int], ...],
|
||||
]
|
||||
|
||||
|
||||
def play(
|
||||
player_hp: int,
|
||||
player_mana: int,
|
||||
player_armor: int,
|
||||
boss_hp: int,
|
||||
boss_attack: int,
|
||||
hard_mode: bool,
|
||||
) -> tuple[tuple[SpellType, int], ...]:
|
||||
winning_node: tuple[tuple[SpellType, int], ...] | None = None
|
||||
|
||||
visited: set[
|
||||
tuple[PlayerType, int, int, int, int, tuple[tuple[BuffType, int], ...]]
|
||||
] = set()
|
||||
nodes: list[Node] = [
|
||||
("player", 0, player_hp, player_mana, player_armor, boss_hp, (), ())
|
||||
]
|
||||
|
||||
while winning_node is None:
|
||||
(
|
||||
player,
|
||||
mana,
|
||||
player_hp,
|
||||
player_mana,
|
||||
player_armor,
|
||||
boss_hp,
|
||||
buffs,
|
||||
spells,
|
||||
) = heapq.heappop(nodes)
|
||||
|
||||
if (player, player_hp, player_mana, player_armor, boss_hp, buffs) in visited:
|
||||
continue
|
||||
|
||||
visited.add((player, player_hp, player_mana, player_armor, boss_hp, buffs))
|
||||
|
||||
if hard_mode and player == "player":
|
||||
player_hp = max(0, player_hp - 1)
|
||||
|
||||
if player_hp == 0:
|
||||
continue
|
||||
|
||||
if boss_hp == 0:
|
||||
winning_node = spells
|
||||
continue
|
||||
|
||||
new_buffs: list[tuple[BuffType, int]] = []
|
||||
for buff, length in buffs:
|
||||
length = length - 1
|
||||
match buff:
|
||||
case "poison":
|
||||
boss_hp = max(boss_hp - 3, 0)
|
||||
case "shield":
|
||||
if length == 0:
|
||||
player_armor -= 7
|
||||
case "recharge":
|
||||
player_mana += 101
|
||||
|
||||
if length > 0:
|
||||
new_buffs.append((buff, length))
|
||||
|
||||
buffs = tuple(new_buffs)
|
||||
|
||||
if player == "boss":
|
||||
heapq.heappush(
|
||||
nodes,
|
||||
(
|
||||
"player",
|
||||
mana,
|
||||
max(0, player_hp - max(boss_attack - player_armor, 1)),
|
||||
player_mana,
|
||||
player_armor,
|
||||
boss_hp,
|
||||
buffs,
|
||||
spells,
|
||||
),
|
||||
)
|
||||
else:
|
||||
buff_types = {b for b, _ in buffs}
|
||||
|
||||
for spell, cost, damage, regeneration in (
|
||||
("magic missile", 53, 4, 0),
|
||||
("drain", 73, 2, 2),
|
||||
):
|
||||
if player_mana < cost:
|
||||
continue
|
||||
|
||||
heapq.heappush(
|
||||
nodes,
|
||||
(
|
||||
"boss",
|
||||
mana + cost,
|
||||
player_hp + regeneration,
|
||||
player_mana - cost,
|
||||
player_armor,
|
||||
max(0, boss_hp - damage),
|
||||
buffs,
|
||||
spells + ((spell, cost),),
|
||||
),
|
||||
)
|
||||
|
||||
for buff_type, buff_cost, buff_length in (
|
||||
("shield", 113, 6),
|
||||
("poison", 173, 6),
|
||||
("recharge", 229, 5),
|
||||
):
|
||||
if buff_type in buff_types:
|
||||
continue
|
||||
|
||||
if player_mana < buff_cost:
|
||||
continue
|
||||
|
||||
heapq.heappush(
|
||||
nodes,
|
||||
(
|
||||
"boss",
|
||||
mana + buff_cost,
|
||||
player_hp,
|
||||
player_mana - buff_cost,
|
||||
player_armor + 7 * (buff_type == "shield"),
|
||||
boss_hp,
|
||||
buffs + ((buff_type, buff_length),),
|
||||
spells + ((buff_type, buff_cost),),
|
||||
),
|
||||
)
|
||||
|
||||
return winning_node
|
||||
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
player_hp = 50
|
||||
player_mana = 500
|
||||
player_armor = 0
|
||||
|
||||
boss_hp = int(lines[0].split(":")[1].strip())
|
||||
boss_attack = int(lines[1].split(":")[1].strip())
|
||||
|
||||
answer_1 = sum(
|
||||
c
|
||||
for _, c in play(player_hp, player_mana, player_armor, boss_hp, boss_attack, False)
|
||||
)
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# 1242 (not working)
|
||||
answer_2 = sum(
|
||||
c for _, c in play(player_hp, player_mana, player_armor, boss_hp, boss_attack, True)
|
||||
)
|
||||
print(f"answer 2 is {answer_2}")
|
2
src/holt59/aoc/inputs/holt59/2015/day22.txt
Normal file
2
src/holt59/aoc/inputs/holt59/2015/day22.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Hit Points: 51
|
||||
Damage: 9
|
Loading…
Reference in New Issue
Block a user