#!/usr/bin/perl -w

use v5.36;
use strict;

my @armies_txt;
{ local $/ = "\n\n"; chomp (@armies_txt = <>); }

my @units = map { parse_army($_) } @armies_txt;
use Data::Dumper;
print Dumper \@units;

sub parse_army($text) {
	my ($name, @rest) = split /\n/, $text;
	$name =~ s/:\z//;
	my $i = 0;
	return ( map { parse_group($name, ++$i, $_) }
		grep { length $_ } @rest );
}

sub parse_group($army, $id, $text) {
	my %rv = ( army => $army, name => "$army group $id", text => $text );
	($rv{units}) = $text =~ /\A(\d+) unit/;
	($rv{hp})    = $text =~ / (\d+) hit point/;
	($rv{damage}, $rv{damage_type})
	             = $text =~ /that does (\d+) (\w+) damage /;
	($rv{init})  = $text =~ /at initiative (\d+)\z/;
	my ($l) = $text =~ /weak to ([^;\)]+)[\);]/;
	
	$rv{weak}    = { map { $_ => 1 } split(/, /, $l) }
		if length $l;
	($l) =  $text =~ /immune to ([^;\)]+)[\);]/;
	$rv{immune}  = { map { $_ => 1 } split(/, /, $l) }
		if length $l;
	$rv{orig_units}  = $rv{units};
	$rv{orig_damage} = $rv{damage};
	return \%rv;
}

sub e_pwr($unit) { return $unit->{units} * $unit->{damage} };

sub damage_to($attacker, $defender) {
	return 0 if $defender->{immune}->{$attacker->{damage_type}};
	my $power = e_pwr($attacker);
	$power *= 2 if $defender->{weak}->{$attacker->{damage_type}};
	return $power;
}

sub selection {
	say "";
	my @rv;
	my %attacked;
	for my $unit (sort {
		$b->{units}*$b->{damage} <=> $a->{units}*$a->{damage}
		|| $b->{init} <=> $a->{init}
	} @units) {
		next if !$unit->{units};
		for my $def (sort {
				damage_to($unit, $b) <=> damage_to($unit, $a)
				|| e_pwr($b) <=> e_pwr($a)
				|| $b->{init} <=> $a->{init}
			}
			grep {
				$_->{army} ne $unit->{army}
				&& $_->{units}
				&& !$attacked{$_->{name}}
			} @units) {
			my $d = damage_to($unit, $def);
			next if !$d;
			say $unit->{name}, ' => ', $def->{name}, ': ', $d;
			$attacked{$def->{name}} = $unit->{name};
			push @rv, [ $unit, $def ];
			last;
		}
	}
	return \@rv;
}

sub attack($items) {
	say "";
	my $total_killed = 0;
	for my $item (sort { $b->[0]->{init} <=> $a->[0]->{init} } @$items) {
		my ($att, $def) = @$item;
		next if !$att->{units};
		my $killed = int(damage_to($att, $def) / $def->{hp});
		$killed = $def->{units} if $killed > $def->{units};
		$total_killed += $killed;

		say "$att->{name} attacks $def->{name} killing $killed units";
		$def->{units} -= $killed;
		$def->{units} = 0 if $def->{units} < 0;
	}
	return $total_killed;
}

sub battle($boost) {
	my $round = 0;

	for my $unit (@units) {
		$unit->{units}  = $unit->{orig_units};
		$unit->{damage} = $unit->{orig_damage};
		$unit->{damage} += $boost
			if $unit->{army} eq 'Immune System';
	}

	say " ################## boost $boost ##################### ";
	while (1) {
		say "round ", $round++;
		my %alive;
		my $sum;
		for my $unit (@units) {
			next if !$unit->{units};
			say "$unit->{name} contains $unit->{units} units";
			$sum += $unit->{units};
			$alive{$unit->{army}}++;
		}
		if (keys(%alive) < 2) {
			say "sum=$sum";
			return $alive{"Immune System"} ? 1 : 0;
		}
		return 0 if !attack(selection());
	}
}

my $boost = 0;
1 while !battle($boost++);

__END__
Immune System:
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
94 units each with 1336 hit points (weak to radiation, cold) with an attack that does 127 bludgeoning damage at initiative 7
1990 units each with 5438 hit points with an attack that does 25 slashing damage at initiative 20

Infection group 4 attacks Immune System group 9 killing 0 units
6523
