Advertisement
musifter

AoC 2023 day 20, part 2 (Perl)

Dec 20th, 2023 (edited)
1,226
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 2.10 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(reduce all);
  8. use Math::Utils     qw(lcm);
  9.  
  10. my %Circ;
  11.  
  12. while (<>) {
  13.     my ($type, $name, $out) = m#(.)(\w+) -> (.*)#;
  14.  
  15.     $name = 'broadcaster' if ($type eq 'b');
  16.  
  17.     my @out = split( /, /, $out );
  18.  
  19.     $Circ{$name}{type} = $type;
  20.     $Circ{$name}{out}  = [@out];
  21.     push( $Circ{$_}{in}->@*, $name )  foreach (@out);
  22. }
  23.  
  24. # Make sure type is defined for everything to avoid warnings
  25. $Circ{$_}{type} //= ''  foreach (keys %Circ);
  26.  
  27. # ASSUME: rx has one input, a NAND gate that collects from several NAND gates.
  28. # Those gates should receive all high at some point on a cycle, and when they
  29. # all line up, rx will receive a low pulse.
  30. my %collect = map { $_ => [] } $Circ{ $Circ{rx}{in}[0] }{in}->@*;
  31. my $presses = 0;
  32.  
  33. LOOP:
  34. while (1) {
  35.     # broadcaster is honourary flip-flop, always start high
  36.     $Circ{broadcaster}{state} = 1;
  37.     my @queue = ([0, 'broadcaster', 'button']);
  38.     $presses++;
  39.  
  40.     PULSE:
  41.     while (my $pulse = shift @queue) {
  42.         my ($bit, $targ, $src) = @$pulse;
  43.  
  44.         next PULSE  if (!$Circ{$targ}{type});   # output from tests
  45.  
  46.         if ($Circ{$targ}{type} eq '&') {
  47.             # NAND
  48.             $Circ{$targ}{$src} = $bit;
  49.  
  50.             my $state = int !(reduce {$a & $b} (1, map {$Circ{$targ}{$_} // 0} $Circ{$targ}{in}->@*));
  51.             push( $collect{$targ}->@*, $presses ) if (exists $collect{$targ} and $state);
  52.  
  53.             push( @queue, map { [$state, $_, $targ] } $Circ{$targ}{out}->@* );
  54.  
  55.         } else {
  56.             # flip-flop or 'b'roadcast
  57.             next PULSE if ($bit);
  58.  
  59.             my $state = $Circ{$targ}{state} = int !($Circ{$targ}{state} // 0);
  60.             push( @queue, map { [$state, $_, $targ] } $Circ{$targ}{out}->@* );
  61.         }
  62.     }
  63.  
  64.     # XXX: Just getting the first appearance of each seems to give us the cycles we want.
  65.     last LOOP  if (all { scalar $collect{$_}->@* } keys %collect);
  66. }
  67.  
  68. say "Sections all set at: ", join( ', ', map { $_->[0] } values %collect );
  69. say "Part 2: ", lcm map { $_->[0] } values %collect;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement