Advertisement
musifter

AoC 2023 day 12 (Perl)

Dec 12th, 2023 (edited)
1,028
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 2.09 KB | Source Code | 0 0
  1. #!/usr/bin/perl
  2.  
  3. use v5.26;
  4. use warnings;
  5.  
  6. use List::Util      qw(sum);
  7.  
  8. no warnings 'recursion';
  9.  
  10. # Get input as array of characters
  11. my @input;
  12. while (<>) {
  13.     my @sec  = split / /;
  14.     my $str  = $sec[0];
  15.     my @nums = map {int} split( /,/, $sec[1] );
  16.  
  17.     push($input[1]->@*, {str => $str, groups => [@nums]});
  18.     push($input[2]->@*, {str => $str . (('?'. $str) x 4), groups => [(@nums) x 5]});
  19. }
  20.  
  21. my %memo;
  22. sub recurse {
  23.     # str to process, current potential group length, groups left to see
  24.     my ($str, $len, @groups) = @_;
  25.  
  26.     # Grab state of params called with to access memo with later.
  27.     my $state = join( $;, $str, $len, @groups );
  28.  
  29.     # Check memo
  30.     return ($memo{$state}) if (exists $memo{$state});
  31.  
  32.     my $ret = 0;
  33.  
  34.     if (!$str) {
  35.         # Out of input, must decide if we found a match:
  36.         # All groups accounted for, no hanging group.
  37.         $ret = 1  if (@groups == 0 and $len == 0);
  38.  
  39.         # Check if hanging group is the size of the only remaining group:
  40.         $ret = 1  if (@groups == 1 and $groups[0] == $len);
  41.  
  42.         return( $memo{$state} = $ret );
  43.     }
  44.  
  45.     # If out of groups, use regex to check if no manditory groups remain
  46.     return( $memo{$state} = ($str =~ m/^[^#]*$/) ) if (!@groups);
  47.  
  48.     # ASSERT: length($str) > 0, $len >= 0, @groups > 0
  49.  
  50.     # Advance one character:
  51.     my $chr = substr( $str, 0, 1, '' );
  52.  
  53.     if ($chr ne '.') {   # ? or #
  54.         # adv making grouping larger
  55.         $ret += &recurse( $str, $len + 1, @groups );
  56.     }
  57.  
  58.     if ($chr ne '#') {   # ? or .
  59.         if ($len == 0) {
  60.             # no current grouping, just advance
  61.             $ret += &recurse( $str, 0, @groups );
  62.  
  63.         } elsif ($len == $groups[0]) {
  64.             # current grouping matches current target
  65.             shift @groups;
  66.             $ret += &recurse( $str, 0, @groups );
  67.         }
  68.         # else: Bad block length!  Fail match, recurse no further
  69.     }
  70.  
  71.     return( $memo{$state} = $ret );
  72. }
  73.  
  74. foreach (1 .. 2) {
  75.     say "Part $_: ", sum map { &recurse( $_->{str}, 0, $_->{groups}->@* ) } $input[$_]->@*;
  76. }
  77.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement