Day 17: Chronospatial Computer

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

  • @vole
    link
    English
    17 days ago

    Raku

    I spent way to much time tweaking the part 2 code to get a working solution. The solution itself is quite simple, though.

    sub MAIN($input) {
        grammar Input {
            token TOP { <register-a> "\n" <register-b> "\n" <register-c> "\n\n" <program> "\n"* }
            token register-a { "Register A: " (\d+) }
            token register-b { "Register B: " (\d+) }
            token register-c { "Register C: " (\d+) }
            token program { "Program: " (\d)+%"," }
        }
        my $parsed = Input.parsefile($input);
        my $register-a = $parsed<register-a>[0].Int;
        my $register-b = $parsed<register-b>[0].Int;
        my $register-c = $parsed<register-c>[0].Int;
        my @program = $parsed<program>[0]>>.Int;
    
        my $part1-solution = run-program($register-a, $register-b, $register-c, @program).join(",");
        say "part1 solution: $part1-solution";
    
        my $part2-solution = search-for-quine(0, $register-b, $register-c, @program, 0);
        say "part2-solution: $part2-solution";
    }
    
    sub run-program($a, $b, $c, @program) {
        my ($register-a, $register-b, $register-c) Z= ($a, $b, $c);
        my $pc = 0;
        my @output;
        while $pc < @program.elems {
            my ($opcode, $operand) Z= @program[$pc, $pc+1];
            my $combo = (given $operand {
                when 0..3 { $operand }
                when 4 { $register-a }
                when 5 { $register-b }
                when 6 { $register-c }
                when 7 { Nil }
                default { say "invalid operand $operand"; exit; }
            });
            given $opcode {
                when 0 { $register-a = $register-a div (2 ** $combo); }
                when 1 { $register-b = $register-b +^ $operand; }
                when 2 { $register-b = $combo mod 8; }
                when 3 { $pc = $operand - 2 if $register-a != 0; }
                when 4 { $register-b = $register-b +^ $register-c; }
                when 5 { @output.push($combo mod 8); }
                when 6 { $register-b = $register-a div (2 ** $combo); }
                when 7 { $register-c = $register-a div (2 ** $combo); }
                default { say "invalid opcode $opcode"; exit; }
            }
            $pc += 2;
        }
        return @output;
    }
    
    sub search-for-quine($a, $b, $c, @program, $idx) {
        return $a if $idx == @program.elems;
        for ^8 {
            my $test-solution = $a * 8 + $_;
            my @output = run-program($test-solution, $b, $c, @program);
            my @program-slice = @program[*-1-$idx..*];
            if @program-slice eqv @output {
                my $found = search-for-quine($test-solution, $b, $c, @program, $idx+1);
                if $found {
                    return $found;
                }
            }
        }
        # Time to back track...
        return False;
    }
    
    • @[email protected]OPM
      link
      fedilink
      17 days ago

      The one disappointing part of part 2 is that there seems to be only one way to do it, which makes it kinda boring from a solutions pov. It is a really nice one though, in the sense that it was (personally) quite hard, but also quite simple when it all clicked into place.