9 Magic Missile costs 53 mana. It instantly does 4 damage.
10 Drain costs 73 mana. It instantly does 2 damage and heals you for 2 hit points.
11 Shield costs 113 mana. It starts an effect that lasts for 6 turns. While it is active, your armor is increased by 7.
12 Poison costs 173 mana. It starts an effect that lasts for 6 turns. At the start of each turn while it is active, it deals the boss 3 damage.
13 Recharge costs 229 mana. It starts an effect that lasts for 5 turns. At the start of each turn while it is active, it gives you 101 new mana.
15 You start with 50 hit points and 500 mana points. The boss's actual stats are in your puzzle input. What is the least amount of mana you can spend and still win the fight? (Do not include mana recharge effects as "spending" negative mana.)
44 my %effects = map { $_ => 1 } qw(shield poison recharge);
47 my ($name, $reqd, $entry, $action) = @_;
48 my ($spent, $state, @spells) = @$entry;
51 return if $ns{mana} < $reqd;
54 $ns{spells} = [ @{ $state->{spells} }, $name ];
55 if ($effects{$name}) {
57 $ns{$name} = $name eq 'recharge' ? 5 : 6;
59 $action->(\%ns) if $action;
60 if ($ns{boss_hp} <= 0) {
61 say "won after spending $spent:_", join(',', @{ $ns{spells} });
65 push_heap @q, [ $spent, \%ns, ];
69 my ($name, $entry, $action) = @_;
70 my ($spent, $state) = @$entry;
71 if ($state->{$name}) {
72 # say "timer $name: $state->{$name}";
75 if ($state->{boss_hp} <= 0) {
76 say "won after spedning $spent: ", join(',', @{ $state->{spells} });
84 do_timer('shield', $entry, sub { });
85 do_timer('poison', $entry, sub { $_[0]->[1]->{boss_hp} -= 3; });
86 do_timer('recharge', $entry, sub { $_[0]->[1]->{mana} += 101; });
90 my $entry = pop_heap @q;
91 my ($spent, $state) = @$entry;
94 if ($state->{turn} & 1) { # boss
96 my $damage = $state->{damage};
97 $damage -= 7 if $state->{shield};
98 $damage = 1 if $damage < 1;
99 $state->{player_hp} -= $damage;
100 say "boss turn $state->{turn} player_hp $state->{player_hp} mana $state->{mana} boss_hp $state->{boss_hp} spent $spent ", join(',', @{ $state->{spells} }), " shield $state->{shield}";
101 if ($state->{player_hp} <= 0) { # boss wins
104 push_heap @q, [$spent, $state ];
108 next if --$state->{player_hp} <= 0;
109 spell('magic_missile', 53, $entry, sub {
110 $_[0]->{boss_hp} -= 4;
112 spell('drain', 73, $entry, sub {
113 $_[0]->{boss_hp} -= 2;
114 $_[0]->{player_hp} += 2;
116 spell('shield', 113, $entry);
117 spell('poison', 173, $entry);
118 spell('recharge', 229, $entry);