]> www.fi.muni.cz Git - aoc.git/blob - 2015/43.pl
Year 2015
[aoc.git] / 2015 / 43.pl
1 #!/usr/bin/perl -w
2
3 use v5.16;
4 use strict;
5
6
7 =comment
8
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.
14
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.)
16
17 Boss: Hit Points: 71
18 Damage: 10
19
20 =cut
21
22 use Array::Heap;
23 my @q;
24 if (1) {
25         push @q, [ 0, {
26                 turn       => 0,
27                 player_hp  => 50,
28                 mana       => 500,
29                 boss_hp    => 71,
30                 damage     => 10,
31                 spells     => [],
32         } ];
33 } else {
34         push @q, [ 0, {
35                 turn       => 0,
36                 player_hp  => 10,
37                 mana       => 250,
38                 boss_hp    => 14,
39                 damage     => 8,
40                 spells     => [],
41         } ];
42 }
43
44 my %effects = map { $_ => 1 } qw(shield poison recharge);
45
46 sub spell {
47         my ($name, $reqd, $entry, $action) = @_;
48         my ($spent, $state, @spells) = @$entry;
49         my %ns = %$state;
50         $ns{turn}++;
51         return if $ns{mana} < $reqd;
52         $ns{mana} -= $reqd;
53         $spent += $reqd;
54         $ns{spells} = [ @{ $state->{spells} }, $name ];
55         if ($effects{$name}) {
56                 return if $ns{$name};
57                 $ns{$name} = $name eq 'recharge' ? 5 : 6;
58         } else {
59                 $action->(\%ns) if $action;
60                 if ($ns{boss_hp} <= 0) {
61                         say "won after spending $spent:_", join(',', @{ $ns{spells} });
62                         exit 0;
63                 }
64         }
65         push_heap @q, [ $spent, \%ns, ];
66 }
67
68 sub do_timer {
69         my ($name, $entry, $action) = @_;
70         my ($spent, $state) = @$entry;
71         if ($state->{$name}) {
72                 # say "timer $name: $state->{$name}";
73                 $action->($entry);
74                 $state->{$name}--;
75                 if ($state->{boss_hp} <= 0) {
76                         say "won after spedning $spent: ", join(',', @{ $state->{spells} });
77                         exit 0;
78                 }
79         }
80 }
81
82 sub do_timers {
83         my ($entry) = @_;
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; });
87 }
88
89 while (@q) {
90         my $entry = pop_heap @q;
91         my ($spent, $state) = @$entry;
92
93         do_timers($entry);
94         if ($state->{turn} & 1) { # boss
95                 $state->{turn}++;
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
102                         next;
103                 }
104                 push_heap @q, [$spent, $state ];
105                 next;
106         }
107         # Player
108         spell('magic_missile', 53, $entry, sub {
109                 $_[0]->{boss_hp} -= 4;
110         });
111         spell('drain', 73, $entry, sub {
112                 $_[0]->{boss_hp} -= 2;
113                 $_[0]->{player_hp} += 2;
114         });
115         spell('shield', 113, $entry);
116         spell('poison', 173, $entry);
117         spell('recharge', 229, $entry);
118 }
119