Advertisement
musifter

AoC 2024, day 17 (Perl)

Dec 17th, 2024 (edited)
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 2.47 KB | Source Code | 0 0
  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. use feature         qw(say);
  7. use List::Util      qw(min);
  8.  
  9. # Read input:
  10. $/ = '';
  11. my @section = map {[split /\n/]} <>;
  12. my @reg  = map {m#(\d+)#g} $section[0]->@*;
  13. my @code = map {m#(\d+)#g} $section[1][0];
  14.  
  15. # Define machine:
  16. use constant  A => 0;
  17. use constant  B => 1;
  18. use constant  C => 2;
  19.  
  20. my $ip = 0;
  21. my @out;
  22.  
  23. # combo operator redirection:
  24. sub c_op ($)   {my $op = shift; return (($op & 04) ? $reg[$op & ~04] : $op)}
  25.  
  26. my @op_str = ('adv', 'bxl', 'bst', 'jnz', 'bxc', 'out', 'bdv', 'cdv');
  27. my %opcodes =
  28.     (
  29.         0 => sub {my $op = c_op shift; $reg[A] = $reg[A] >> $op},           # adv
  30.         6 => sub {my $op = c_op shift; $reg[B] = $reg[A] >> $op},           # bdv
  31.         7 => sub {my $op = c_op shift; $reg[C] = $reg[A] >> $op},           # cdv
  32.  
  33.         1 => sub {my $op = shift;      $reg[B] ^= $op},                     # bxl
  34.         4 => sub {my $op = shift;      $reg[B] ^= $reg[C]},                 # bxc
  35.  
  36.         2 => sub {my $op = c_op shift; $reg[B] = $op % 8},                  # bst
  37.         5 => sub {my $op = c_op shift; push(@out, $op % 8)},                # out
  38.  
  39.         3 => sub {my $op = shift;      $ip = ($reg[A]) ? $op - 2 : $ip},    # jnz
  40.     );
  41.  
  42. # Part 1:
  43. # Run machine:
  44. while ($ip < @code - 1) {
  45.     &{$opcodes{$code[$ip]}}( $code[$ip+1] );
  46.     $ip += 2;
  47. }
  48.  
  49. say "Part 1: ", join(',', @out);
  50.  
  51. # Part 2:
  52. # Run code until jump.
  53. sub try_code {
  54.     # Reset machine with argument in A register:
  55.     @reg = (shift, 0, 0);
  56.     @out = ();
  57.     $ip = 0;
  58.  
  59.     while ($ip < @code - 1 && $code[$ip] != 3) {    # halt on jnz (or end)
  60.         &{$opcodes{$code[$ip]}}( $code[$ip+1] );
  61.         $ip += 2;
  62.     }
  63.  
  64.     return ($out[0]);
  65. }
  66.  
  67. # ASSUME:
  68. # - Code is deconstructed A by shifting it in a loop (true of input and test 2).
  69. # - The loop outputs one value each time.
  70. # - Higher order bits of A will be involved in the calculation for the input.
  71.  
  72. # So we go in reverse because the we know what the high bits can possibly be while testing.
  73. # We may get multiple octal digits that can solve the partial that we need to track.
  74. my %poss = (0 => 1);
  75. foreach my $digit (reverse @code) {
  76.     my %new_poss;
  77.  
  78.     # shift left possibilities one octal digit and try all 8 lower options
  79.     foreach my $val (map {($_<<3) .. ($_<<3) + 7} keys %poss) {
  80.         if ($digit == &try_code( $val )) {
  81.             $new_poss{$val}++;
  82.         }
  83.     }
  84.     %poss = %new_poss;
  85. }
  86.  
  87. say "Part 2: ", min keys %poss;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement