7 { local $/ = "\n\n"; chomp (@armies_txt = <>); }
9 my @units = map { parse_army($_) } @armies_txt;
13 sub parse_army($text) {
14 my ($name, @rest) = split /\n/, $text;
17 return ( map { parse_group($name, ++$i, $_) }
18 grep { length $_ } @rest );
21 sub parse_group($army, $id, $text) {
22 my %rv = ( army => $army, name => "$army group $id", text => $text );
23 ($rv{units}) = $text =~ /\A(\d+) unit/;
24 ($rv{hp}) = $text =~ / (\d+) hit point/;
25 ($rv{damage}, $rv{damage_type})
26 = $text =~ /that does (\d+) (\w+) damage /;
27 ($rv{init}) = $text =~ /at initiative (\d+)\z/;
28 my ($l) = $text =~ /weak to ([^;\)]+)[\);]/;
30 $rv{weak} = { map { $_ => 1 } split(/, /, $l) }
32 ($l) = $text =~ /immune to ([^;\)]+)[\);]/;
33 $rv{immune} = { map { $_ => 1 } split(/, /, $l) }
35 $rv{orig_units} = $rv{units};
36 $rv{orig_damage} = $rv{damage};
40 sub e_pwr($unit) { return $unit->{units} * $unit->{damage} };
42 sub damage_to($attacker, $defender) {
43 return 0 if $defender->{immune}->{$attacker->{damage_type}};
44 my $power = e_pwr($attacker);
45 $power *= 2 if $defender->{weak}->{$attacker->{damage_type}};
54 $b->{units}*$b->{damage} <=> $a->{units}*$a->{damage}
55 || $b->{init} <=> $a->{init}
57 next if !$unit->{units};
59 damage_to($unit, $b) <=> damage_to($unit, $a)
60 || e_pwr($b) <=> e_pwr($a)
61 || $b->{init} <=> $a->{init}
64 $_->{army} ne $unit->{army}
66 && !$attacked{$_->{name}}
68 my $d = damage_to($unit, $def);
70 say $unit->{name}, ' => ', $def->{name}, ': ', $d;
71 $attacked{$def->{name}} = $unit->{name};
72 push @rv, [ $unit, $def ];
82 for my $item (sort { $b->[0]->{init} <=> $a->[0]->{init} } @$items) {
83 my ($att, $def) = @$item;
84 next if !$att->{units};
85 my $killed = int(damage_to($att, $def) / $def->{hp});
86 $killed = $def->{units} if $killed > $def->{units};
87 $total_killed += $killed;
89 say "$att->{name} attacks $def->{name} killing $killed units";
90 $def->{units} -= $killed;
91 $def->{units} = 0 if $def->{units} < 0;
99 for my $unit (@units) {
100 $unit->{units} = $unit->{orig_units};
101 $unit->{damage} = $unit->{orig_damage};
102 $unit->{damage} += $boost
103 if $unit->{army} eq 'Immune System';
106 say " ################## boost $boost ##################### ";
108 say "round ", $round++;
111 for my $unit (@units) {
112 next if !$unit->{units};
113 say "$unit->{name} contains $unit->{units} units";
114 $sum += $unit->{units};
115 $alive{$unit->{army}}++;
117 if (keys(%alive) < 2) {
119 return $alive{"Immune System"} ? 1 : 0;
121 return 0 if !attack(selection());
126 1 while !battle($boost++);
130 889 units each with 3275 hit points (weak to bludgeoning, radiation; immune to cold) with an attack that does 36 bludgeoning damage at initiative 12
131 94 units each with 1336 hit points (weak to radiation, cold) with an attack that does 127 bludgeoning damage at initiative 7
132 1990 units each with 5438 hit points with an attack that does 25 slashing damage at initiative 20
134 Infection group 4 attacks Immune System group 9 killing 0 units