Browse Source

Add solutions for day 12

Oliver Youle 2 years ago
parent
commit
eb841d88bf
2 changed files with 157 additions and 0 deletions
  1. 89 0
      lib/AoC/Solution/Day12.pm
  2. 68 0
      t/AoC/Solution/Day12.t

+ 89 - 0
lib/AoC/Solution/Day12.pm

@@ -0,0 +1,89 @@
+package AoC::Solution::Day12;
+
+use Modern::Perl;
+
+use List::Util qw(first);
+use Moo;
+
+with 'AoC::Solution';
+
+sub part_1 {
+    my $self = shift;
+
+    my $paths = $self->_traverse_caves_1('start');
+
+    return scalar @$paths;
+}
+
+sub part_2 {
+    my $self = shift;
+
+    my $paths = $self->_traverse_caves_2(undef, 'start');
+
+    return scalar @$paths;
+}
+
+sub _traverse_caves_1 {
+    my ($self, @current_path) = @_;
+
+    my $label = $current_path[-1];
+
+    return [\@current_path] if $label eq 'end';
+
+    my $node = $self->input->{$label};
+
+    my @paths;
+    foreach my $connection (@$node) {
+        if ($connection =~ /^[A-Z]+$/ || !first { $_ eq $connection } @current_path) {
+            push @paths, @{ $self->_traverse_caves_1(@current_path, $connection) };
+        }
+    }
+    return \@paths;
+}
+
+sub _traverse_caves_2 {
+    my ($self, $small_cave, @current_path) = @_;
+
+    my $label = $current_path[-1];
+
+    return [\@current_path] if $label eq 'end';
+
+    my $node = $self->input->{$label};
+
+    my @paths;
+    foreach my $connection (@$node) {
+        if ($connection =~ /^[A-Z]+$/) {
+            push @paths, @{ $self->_traverse_caves_2($small_cave, @current_path, $connection) };
+        }
+        elsif ($connection ne 'start') {
+            my $times_seen = grep { $_ eq $connection } @current_path;
+            if ($times_seen) {
+                if ($small_cave && $connection eq $small_cave && $times_seen == 1) {
+                    push @paths, @{ $self->_traverse_caves_2($small_cave, @current_path, $connection) };
+                }
+                elsif (!$small_cave) {
+                    push @paths, @{ $self->_traverse_caves_2($connection, @current_path, $connection) };
+                }
+            }
+            else {
+                push @paths, @{ $self->_traverse_caves_2($small_cave, @current_path, $connection) };
+            }
+        }
+    }
+    return \@paths;
+}
+
+sub _parse_input {
+    my $self = shift;
+
+    my %cave_system;
+    foreach my $line (split(/\n/, $self->input)) {
+        my ($node, $connection) = split(/-/, $line);
+        push @{ $cave_system{$node} }, $connection;
+        push @{ $cave_system{$connection} }, $node;
+    }
+
+    return \%cave_system;
+}
+
+1;

+ 68 - 0
t/AoC/Solution/Day12.t

@@ -0,0 +1,68 @@
+#!/usr/bin/env perl
+
+use Modern::Perl;
+
+use AoC::Solution::Day12;
+
+use Test::More;
+
+my $solution = AoC::Solution::Day12->new(
+    input => join("\n", (
+        'start-A',
+        'start-b',
+        'A-c',
+        'A-b',
+        'b-d',
+        'A-end',
+        'b-end',
+    )),
+);
+
+is($solution->part_1, 10, 'part_1_a');
+is($solution->part_2, 36, 'part_2_a');
+
+$solution = AoC::Solution::Day12->new(
+    input => join("\n", (
+        'dc-end',
+        'HN-start',
+        'start-kj',
+        'dc-start',
+        'dc-HN',
+        'LN-dc',
+        'HN-end',
+        'kj-sa',
+        'kj-HN',
+        'kj-dc',
+    )),
+);
+
+is($solution->part_1, 19, 'part_1_b');
+is($solution->part_2, 103, 'part_2_b');
+
+$solution = AoC::Solution::Day12->new(
+    input => join("\n", (
+        'fs-end',
+        'he-DX',
+        'fs-he',
+        'start-DX',
+        'pj-DX',
+        'end-zg',
+        'zg-sl',
+        'zg-pj',
+        'pj-he',
+        'RW-he',
+        'fs-DX',
+        'pj-RW',
+        'zg-RW',
+        'start-pj',
+        'he-WI',
+        'zg-he',
+        'pj-fs',
+        'start-RW',
+    )),
+);
+
+is($solution->part_1, 226, 'part_1_c');
+is($solution->part_2, 3509, 'part_2_c');
+
+done_testing();