7 { local $/ = "\n\n"; chomp (@armies_txt = <>); }
9 my @units = map { parse_army($_) } @armies_txt;
11 # print Dumper \@units;
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{hp}) = $text =~ / (\d+) hit point/;
26 ($rv{damage}, $rv{damage_type})
27 = $text =~ /that does (\d+) (\w+) damage /;
28 ($rv{init}) = $text =~ /at initiative (\d+)\z/;
30 map { defined $_ ? ($_ => 1) : () }
31 $text =~ /weak to (\w+)(?:, (\w+))*/
34 map { defined $_ ? ($_ => 1) : () }
35 $text =~ /immune to (\w+)(?:, (\w+))*/
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 ];
81 for my $item (sort { $b->[0]->{init} <=> $a->[0]->{init} } @$items) {
82 my ($att, $def) = @$item;
83 next if !$att->{units};
84 my $killed = int(damage_to($att, $def) / $def->{hp});
85 $killed = $def->{units} if $killed > $def->{units};
87 say "$att->{name} attacks $def->{name} killing $killed units";
88 $def->{units} -= $killed;
89 $def->{units} = 0 if $def->{units} < 0;
95 say "round ", $round++;
98 for my $unit (@units) {
99 next if !$unit->{units};
100 say "$unit->{name} contains $unit->{units} units";
101 $sum += $unit->{units};
102 $alive{$unit->{army}}++;
104 if (keys(%alive) < 2) {
113 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
114 94 units each with 1336 hit points (weak to radiation, cold) with an attack that does 127 bludgeoning damage at initiative 7
115 1990 units each with 5438 hit points with an attack that does 25 slashing damage at initiative 20