muthm

AoC [2025 Day 5] [LANGUAGE: Perl]

Dec 5th, 2025
18
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 3.06 KB | Source Code | 0 0
  1. #!/usr/bin/env perl
  2. #
  3. #       Advent of Code 2025
  4. #       --- Day 5: Cafeteria ---
  5. #       Solution in Perl by Matthias Muth (muthm).
  6. #
  7.  
  8. use v5.36;
  9.  
  10. sub puzzle( $input ) {
  11.  
  12.     my ( @fresh_ranges, @availables );
  13.     for ( split "\n", $input ) {
  14.         /^(\d+)-(\d+)/ and do { push @fresh_ranges, [ $1, $2 ]; next };
  15.         /^(\d+)/       and do { push @availables, $1;           next };
  16.     }
  17.     # Sort the ranges by their 'from' value, lowest to highest,
  18.     # and sort the availables, lowest to highest.
  19.     @fresh_ranges = sort { $a->[0] <=> $b->[0] } @fresh_ranges;
  20.     @availables = sort { $a <=> $b } @availables;
  21.  
  22.     # Part 1
  23.     # Move through the (sorted) availables, while at the same time moving
  24.     # through the (sorted) ranges in sync using a 'current range'.
  25.     # The 'current range' is the first range that *may* include the
  26.     # current loop value because it has a 'to' value that is higher.
  27.     # As the ranges are sorted by their 'from' value, all the ranges
  28.     # from left to right will be considered correctly.
  29.  
  30.     # Initialize the first range.
  31.     my $current_range = 0;
  32.     my ( $range_from, $range_to ) = $fresh_ranges[$current_range]->@*;
  33.  
  34.     my $fresh_count = 0;
  35.     for ( @availables ) {
  36.  
  37.         # Skip to next range that has a higher 'to' value
  38.         # if we have left the current range.
  39.         while ( $_ > $range_to && ++$current_range <= $#fresh_ranges ) {
  40.             ( $range_from, $range_to ) = $fresh_ranges[$current_range]->@*;
  41.         }
  42.  
  43.         # End the loop if we have passed beyond the last range.
  44.         last if $_ > $range_to;
  45.  
  46.         # Increment the count if the current value is inside the current range.
  47.         # Only the 'from' value needs to be checked, because the 'to' value
  48.         # is certain to be higher at this point.
  49.         ++$fresh_count
  50.             if $_ >= $range_from;
  51.     }
  52.     my $part_1_result = $fresh_count;
  53.  
  54.     # Part 2:
  55.     # Using the ranges sorted by their 'from' values, add the number
  56.     # of items in each range.
  57.     # To deal with overlapping ranges, keep the highest 'to' value that was
  58.     # processed, and adjust the 'from' value of subsequent ranges to start
  59.     # right after it, if necessary.
  60.     my $last_processed = 0;
  61.     $fresh_count = 0;
  62.     for ( @fresh_ranges ) {
  63.         ( $range_from, $range_to ) = $_->@*;
  64.         next if $last_processed >= $range_to;
  65.         $range_from = $last_processed + 1
  66.             if $last_processed >= $range_from;
  67.         $fresh_count += $range_to - $range_from + 1
  68.             if $range_from <= $range_to;
  69.         $last_processed = $range_to;
  70.     }
  71.     my $part_2_result = $fresh_count;
  72.  
  73.     return ( $part_1_result, $part_2_result );
  74. }
  75.  
  76. # Usage: no command line arguments: run the example from the __DATA__section,
  77. #        else read input data from the file given (or stdin if the file is '-').
  78. chomp( my $input = join "", @ARGV ? <> : <DATA> );
  79. my @results = puzzle( $input );
  80. say "part 1 answer: ", $results[0];
  81. say "part 2 answer: ", $results[1];
  82.  
  83. __DATA__
  84. 3-5
  85. 10-14
  86. 16-20
  87. 12-18
  88.  
  89. 1
  90. 5
  91. 8
  92. 11
  93. 17
  94. 32
  95.  
Tags: AoC2025
Add Comment
Please, Sign In to add comment