musifter

AoC 2016, pay 16 (Perl)

Feb 16th, 2026 (edited)
273
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 1.71 KB | Source Code | 0 0
  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. use feature     qw(say);
  7.  
  8. my $seed = <>;
  9. chomp $seed;
  10.  
  11. # Table of tail parities:
  12. my $par = 0;
  13. my @Table = (0, map {$par ^= $_} split( //, $seed ));
  14. $par = 0;
  15. push( @Table, 0, map {$par ^= !$_} split( //, reverse $seed ) );
  16.  
  17. my $Block_Size = length( $seed ) + 1;
  18.  
  19. my $Odd_Parity = @{[$seed =~ m#1#g]} % 2;
  20. my $Odd_Length = length( $seed ) % 2;
  21.  
  22. # Returns A255070(n+1) & 1:
  23. # The parity of 1s at index n of the dragon curve starting with "0".
  24. # A255070 is (1/2)*(n - #runs in binary expansion of n)
  25. sub dragon_parity {
  26.     my $n = shift;
  27.  
  28.     $n++;
  29.     my $num = $n ^ ($n >> 1);
  30.  
  31.     # Count bits using classic bit iterator
  32.     my $bitcount = 0;
  33.     for ($bitcount = 0; $num; $bitcount++) {
  34.         $num &= $num - 1;
  35.     }
  36.  
  37.     return ((($n - $bitcount) >> 1) & 1);
  38. }
  39.  
  40. sub calc_chksum {
  41.     my $data_length = shift;
  42.  
  43.     # Data length is divided into sections of the largest power of 2 that divides it
  44.     my $sect_size  = $data_length & ~($data_length - 1);
  45.     my $chksum_len = $data_length / $sect_size;
  46.  
  47.     my $result = '';
  48.     my $prev = 0;
  49.     foreach my $sect (1 .. $chksum_len) {
  50.         my $end   = $sect * $sect_size;
  51.         my $index = int($end / $Block_Size) * 2 - 1;
  52.  
  53.         my $full = &dragon_parity( $Odd_Length ? $index : int($index/2) );
  54.         $full ^= $Table[$end % ($Block_Size * 2)];          # add parity of tail
  55.         $full ^= 1  if ($Odd_Parity and $index % 4 < 2);    # odd seed adjustment
  56.  
  57.         $result .= ($prev ^ $full ^ 1);                     # want range and complement
  58.         $prev = $full;
  59.     }
  60.  
  61.     return ($result);
  62. }
  63.  
  64. say "Part 1: ", &calc_chksum( 272 );
  65. say "Part 2: ", &calc_chksum( 35651584 );
  66.  
Advertisement
Add Comment
Please, Sign In to add comment