Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/perl
- use strict;
- use warnings;
- # Helpful chain iterator:
- sub chain (&@) {
- my $block = shift;
- return (map { &$block( $_[$_-1], $_[$_] ) } (1 .. $#_));
- }
- # Read in data
- chomp( $_ = <> );
- my @poly = split //;
- my @Ends = ($poly[-1], $poly[0]);
- <>; # toss blank line
- my %Rules = map { chomp; split / -> /, $_ } <>;
- # Convert pair count hash into letter counts and give diff between max and min
- sub get_letter_diff (\%) {
- my $pairs = shift;
- # plus one to ends to account for sides "off edges"
- my %letters = ($Ends[0] => 1, $Ends[1] => 1);
- foreach my $pair (keys %$pairs) {
- $letters{$_} += $pairs->{$pair} foreach (split //, $pair);
- }
- # half because we count each from both sides
- %letters = map { $_ => $letters{$_} / 2 } keys %letters;
- # don't actually care about the letters, just look at values now
- my @sort = sort { $a <=> $b } values %letters;
- return ($sort[-1] - $sort[0]);
- }
- # Load counts with the chain iterator
- my %counts = chain { join('', @_) => 1 } @poly;
- # Run 40 steps of polymer insersions (output part 1 at 10)
- foreach my $time (1 .. 40) {
- my %new_counts;
- foreach my $pair (keys %counts) {
- my @parts = split //, $pair;
- # Note: all possible rules definted so this works
- $new_counts{"$parts[0]$Rules{$pair}"} += $counts{$pair};
- $new_counts{"$Rules{$pair}$parts[1]"} += $counts{$pair};
- }
- %counts = %new_counts;
- print "Part 1: ", &get_letter_diff( \%counts ), "\n" if ($time == 10);
- }
- print "Part 2: ", &get_letter_diff( \%counts ), "\n";
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement