Advertisement
mscha

AoC 2016 day 23

Dec 23rd, 2016
501
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 6 6.73 KB | None | 0 0
  1. #!/usr/bin/env perl6
  2.  
  3. use v6.c;
  4.  
  5. class Computer
  6. {
  7.     has @.instructions;
  8.     has @.optimized;
  9.     has @.code;
  10.     has Int $.pos = 0;
  11.     has Int $.counter = 0;
  12.     has %.register = :a(0), :b(0), :c(0), :d(0);
  13.     has Bool $.verbose = False;
  14.  
  15.     constant %TOGGLE = { :inc<dec>, :dec<inc>, :tgl<inc>, :jnz<cpy>, :cpy<jnz> };
  16.  
  17.     method compile-line($pos)
  18.     {
  19.         my token reg { <[abcd]> };
  20.         my token val { '-'? \d+ }
  21.  
  22.         @!optimized[$pos] = '';
  23.  
  24.         given @!instructions[$pos] {
  25.             when m:s/^ cpy <val> <reg> $/ {
  26.                 my $val = +$<val>;
  27.                 my $reg = ~$<reg>;
  28.                 return { %!register{$reg} = $val };
  29.             }
  30.             when m:s/^ cpy <reg> <reg> $/ {
  31.                 my $regFrom = ~$<reg>[0];
  32.                 my $regTo = ~$<reg>[1];
  33.                 return { %!register{$regTo} = %!register{$regFrom} };
  34.             }
  35.             when m:s/^ inc <reg> $/ {
  36.                 my $reg = ~$<reg>;
  37.  
  38.                 # See if we can optimize away a loop
  39.                 if $pos < +@!instructions - 2 && @!instructions[$pos+1] ~~ m:s/^ dec <reg> $/ {
  40.                     my $reg2 = ~$<reg>;
  41.                     if $reg2 ne $reg && @!instructions[$pos+2] ~~ m:s/^ jnz $reg2 '-2' $/ {
  42.                         if $pos < +@!instructions - 4 && @!instructions[$pos+3] ~~ m:s/^ dec <reg> $/ {
  43.                             my $reg3 = ~$<reg>;
  44.                             if $reg3 ne $reg|$reg2 && @!instructions[$pos+4] ~~ m:s/^ jnz $reg3 '-5' $/ {
  45.                                 # Multiplication
  46.                                 @!optimized[$pos] = "$reg += $reg2 * $reg3; $reg2 = $reg3 = 0";
  47.                                 return { %!register{$reg} += %!register{$reg2} * %!register{$reg3};
  48.                                          %!register{$reg2} = 0;
  49.                                          %!register{$reg3} = 0;
  50.                                          $!pos = $pos+5; };
  51.                             }
  52.                         }
  53.  
  54.                         # Addition
  55.                         @!optimized[$pos] = "$reg += $reg2; $reg2 = 0";
  56.                         return { %!register{$reg} += %!register{$reg2};
  57.                                  %!register{$reg2} = 0;
  58.                                  $!pos = $pos+3; }
  59.                     }
  60.                 }
  61.  
  62.                 # Unoptimized increment
  63.                 return { %!register{$reg}++ };
  64.             }
  65.             when m:s/^ dec <reg> $/ {
  66.                 my $reg = ~$<reg>;
  67.  
  68.                 # See if we can optimize away a loop
  69.                 if $pos < +@!instructions - 2 && @!instructions[$pos+1] ~~ m:s/^ inc <reg> $/ {
  70.                     my $reg2 = ~$<reg>;
  71.                     if $reg2 ne $reg && @!instructions[$pos+2] ~~ m:s/^ jnz $reg '-2' $/ {
  72.                         if $pos < +@!instructions - 4 && @!instructions[$pos+3] ~~ m:s/^ dec <reg> $/ {
  73.                             my $reg3 = ~$<reg>;
  74.                             if $reg3 ne $reg|$reg2 && @!instructions[$pos+4] ~~ m:s/^ jnz $reg3 '-5' $/ {
  75.                                 # Multiplication
  76.                                 @!optimized[$pos] = "$reg2 += $reg * $reg3; $reg = $reg3 = 0";
  77.                                 return { %!register{$reg2} += %!register{$reg} * %!register{$reg3};
  78.                                          %!register{$reg} = 0;
  79.                                          %!register{$reg3} = 0;
  80.                                          $!pos = $pos+5; };
  81.                             }
  82.                         }
  83.  
  84.                         # Addition
  85.                         @!optimized[$pos] = "$reg2 += $reg; $reg = 0";
  86.                         return { %!register{$reg2} += %!register{$reg};
  87.                                  %!register{$reg} = 0;
  88.                                  $!pos = $pos+3;}
  89.                     }
  90.                 }
  91.  
  92.                 # Unoptimized decrement
  93.                 return { %!register{$reg}-- };
  94.             }
  95.             when m:s/^ jnz <nonzero=val> <offset=val> $/ {
  96.                 my $nonzero = +$<nonzero>;
  97.                 my $offset = $<offset>;
  98.                 return { $!pos = $pos + $offset if $nonzero };
  99.             }
  100.             when m:s/^ jnz <nonzero=reg> <offset=val> $/ {
  101.                 my $nonzero = ~$<nonzero>;
  102.                 my $offset = $<offset>;
  103.                 return { $!pos = $pos + $offset if %!register{$nonzero} };
  104.             }
  105.             when m:s/^ jnz <nonzero=val> <offset=reg> $/ {
  106.                 my $nonzero = +$<nonzero>;
  107.                 my $offset = $<offset>;
  108.                 return { $!pos = $pos + %!register{$offset} if $nonzero };
  109.             }
  110.             when m:s/^ jnz <nonzero=reg> <offset=reg> $/ {
  111.                 my $nonzero = ~$<nonzero>;
  112.                 my $offset = $<offset>;
  113.                 return { $!pos = $pos + %!register{$offset} if %!register{$nonzero} };
  114.             }
  115.             when m:s/^ tgl <val> $/ {
  116.                 my $val = $<val>;
  117.                 return { self.toggle($pos+$val) };
  118.             }
  119.             when m:s/^ tgl <reg> $/ {
  120.                 my $reg = ~$<reg>;
  121.                 return { self.toggle($pos+%!register{$reg}) };
  122.             }
  123.             default {
  124.                 die "Invalid instruction: $_";
  125.             }
  126.         }
  127.     }
  128.  
  129.     method compile()
  130.     {
  131.         say "Compiling..." if $!verbose;
  132.  
  133.         @!code = gather for 0..^@!instructions -> $pos {
  134.             take self.compile-line($pos);
  135.         }
  136.     }
  137.  
  138.     method toggle(Int $pos)
  139.     {
  140.         return unless @!instructions[$pos];
  141.  
  142.         my ($instr, $args) = @!instructions[$pos].split(' ', 2);
  143.         die "Don't know how to toggle '$instr'" unless %TOGGLE{$instr};
  144.         @!instructions[$pos] = "%TOGGLE{$instr} $args";
  145.  
  146.         # We need to recompile the whole program, since the code may have been part of a
  147.         # loop that was optimized away.
  148.         self.compile();
  149.     }
  150.  
  151.     method run()
  152.     {
  153.         self.compile unless @!code;
  154.  
  155.         while @!code[$!pos] {
  156.             $!counter++;
  157.             say "$!pos: (%!register<a b c d>.join(' ')) ",
  158.                             @!optimized[$!pos] ?? "@!optimized[$!pos] [optimized]"
  159.                                                !! @!instructions[$!pos] if $!verbose;
  160.             @!code[$!pos++]();
  161.         }
  162.     }
  163. }
  164.  
  165. sub MAIN(IO() $inputfile where *.f, Int :$a=12, Int :$b=0, Int :$c=0, Int :$d=0, Bool :v(:$verbose))
  166. {
  167.     my $computer = Computer.new(:instructions($inputfile.lines), :$verbose);
  168.     $computer.register<a b c d> = $a, $b, $c, $d;
  169.     $computer.run;
  170.  
  171.     say '' if $verbose;
  172.     say "The state of the register: ",
  173.          $computer.register.pairs.sort.map({ "$_.key()=$_.value()"}).join(', ');
  174.     say "$computer.counter() instructions processed.";
  175. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement