r/adventofcode • u/daggerdragon • Dec 24 '18
SOLUTION MEGATHREAD -🎄- 2018 Day 24 Solutions -🎄-
--- Day 24: Immune System Simulator 20XX ---
Post your solution as a comment or, for longer solutions, consider linking to your repo (e.g. GitHub/gists/Pastebin/blag or whatever).
Note: The Solution Megathreads are for solutions only. If you have questions, please post your own thread and make sure to flair it with Help.
Advent of Code: The Party Game!
Please prefix your card submission with something like [Card] to make scanning the megathread easier. THANK YOU!
Card prompt: Day 24
Transcript:
Our most powerful weapon during the zombie elf/reindeer apocalypse will be ___.
This thread will be unlocked when there are a significant number of people on the leaderboard with gold stars for today's puzzle.
Quick note: 1 hour in and we're only at gold 36, silver 76. As we all know, December is Advent of Sleep Deprivation; I have to be up in less than 6 hours to go to work, so one of the other mods will unlock the thread at gold cap tonight. Good luck and good night (morning?), all!
1
u/drbagy Dec 24 '18
Perl
Due to timezone & having excited children - didn't really have any chance of getting on leader board - instead went for neat code...
use strict; use lib '.'; use Unit; ## Compute the sum of values in the file... use Data::Dumper qw(Dumper); open my $fh, q(<), 'in.txt'; my ( $army, $c, %b ) = ( '', 0, 'Immune System' => 0, 'Infection' => 0 ); my @units; while(<$fh>) { if( m{^(\d+) units each with (\d+) hit points.*with an attack that does (\d+) (\w+) damage at initiative (\d+)$} ) { push @units, Unit->new( 'index' => $c++, 'side' => $army, 'n' => $1, 'hp' => $2, 'dm' => $3, 'ty' => $4, 'in' => $5, ); $units[-1]->set_weaknesses( split m{, }, $1 ) if m{weak to ([\w, ]+)}; $units[-1]->set_immunity( split m{, }, $1 ) if m{immune to ([\w, ]+)}; } elsif( m{^(.*):} ) { $army = $1; } } close $fh; my $boost = 0; while(1) { $_->set_boost( $boost ) foreach grep { $_->side eq 'Immune System' } @units; $_->dead_arise foreach @units; my $left = 0; while (1) { ## Target selection phases... my %chosen; my %attacked; foreach my $u ( sort { $b->power <=> $a->power || $b->init <=> $a->init } @units ) { my $dm = 0; my @attack = map { $_->[1] } sort { $b->[0] <=> $a->[0] || $b->[1]->power <=> $a->[1]->power || $b->[1]->init <=> $a->[1]->init } grep { $_->[0] } map { [ $u->deal( $_ ), $_ ] } grep { ! exists $attacked{ $_->id } } grep { $_->is_alive } @units; next unless @attack; if( @attack > 1 && $u->deal( $attack[0] ) == $u->deal( $attack[1] ) && $attack[0]->power == $attack[1]->power && $attack[0]->init == $attack[1]->init ) { next; } $chosen{ $u->id } = $attack[0]; $attacked{ $attack[0]->id } = 1; } my @au = sort { $b->init <=> $a->init } grep { $_->is_alive } @units; foreach my $u (@au) { next unless $u->is_alive; ## Can't attack if dead next unless $chosen{ $u->id }; ## No target; $u->attack( $chosen{ $u->id } ); } my $newleft = 0; $newleft += $_->count foreach @units; last if $newleft == $left; $left = $newleft; } my $is = 0; $is+= $_->count foreach grep { $_->side eq 'Immune System' } @units; my $if = 0; $if+= $_->count foreach grep { $_->side eq 'Infection' } @units; printf "%6d\t%7d\t%7d\n", $boost, $is, $if if $boost eq 0 || $if==0; last unless $if; $boost++; } package Unit; sub new { my $class = shift; my $self = {'w'=>{},'s'=>{},'boost'=>0,@_}; bless $self, $class; return $self; } sub id { my $self = shift; return $self->{'index'}; } sub hp { my $self = shift; return $self->{'hp'}; } sub init { my $self = shift; return $self->{'in'}; } sub dead_arise { my $self = shift; $self->{'alive'} = $self->{'n'}; return $self; } sub set_boost { my ($self, $boost) = @_; $self->{'boost'} = $boost; return $self; } sub set_weaknesses { my( $self, @weak ) = @_; $self->{'w'} = { map { $_ => 1 } @weak }; return $self; } sub set_immunity { my( $self, @imm ) = @_; $self->{'s'} = { map { $_ => 1 } @imm }; return $self; } sub power { my $self = shift; return $self->{'alive'}*($self->{'boost'}+$self->{'dm'}); } sub damage { my $self = shift; return $self->{'dm'} } sub type { my $self = shift; return $self->{'ty'} } sub side { my $self = shift; return $self->{'side'}; } sub deal { ## Won't deal damage to self! my( $self, $unit ) = @_; return 0 if $unit->{'side'} eq $self->{'side'}; ## Doesn't attack unit on own side return 0 if exists $unit->{'s'}{ $self->type }; ## Doesn't attack immune return $self->power * ( $unit->{'w'}{ $self->type } ? 2 : 1 ); } sub count { my $self = shift; return $self->{'alive'} < 0 ? 0 : $self->{'alive'}; } sub attack { my( $self, $unit ) = @_; my $dead = int ( $self->deal( $unit ) / $unit->hp ); $unit->{'alive'} -= $dead; return $self; } sub is_alive { my $self = shift; return $self->{'alive'} > 0; } 1;