use v6.d; enum opcode ( halt => 99, add => 1, multiply => 2 ); class X::Halt is Exception {} class IntcodeVM is export { has @.program; has @.memory; # Program counter has $!pc = 0; submethod new(Str $program) { my @program = $program.split(',').map(*.Int); self.bless(:@program, :memory(@program)); } method run { loop { CATCH { when X::Halt { last } } self!run-next-command; } } method reset-memory { @!memory = @.program; $!pc = 0; } method !run-next-command { given self!peek-opcode { when halt { die X::Halt.new; } when add { self!add(); $!pc += 4; } when multiply { self!multiply(); $!pc += 4; } default { die "Unknwon opcode {self!peek-opcode()}"; } } } method !peek-opcode(--> Int) { die "$!pc exceeds memory {@!memory.elems}" if $!pc >= @!memory.elems; @!memory[$!pc] } method !program-chunk(Range $r) { @!memory[$r + $!pc] } method !add { my ($opcode, $mem1, $mem2, $memresult) = self!program-chunk(^4); @!memory[$memresult] = @!memory[$mem1] + @!memory[$mem2]; } method !multiply { my ($opcode, $mem1, $mem2, $memresult) = self!program-chunk(^4); @!memory[$memresult] = @!memory[$mem1] * @!memory[$mem2]; } method output { @!memory[0] } } sub try-inputs(IntcodeVM $vm, $noun, $verb) { $vm.reset-memory(); $vm.memory[1] = $noun; $vm.memory[2] = $verb; $vm.run; say $vm.memory[^3]; return $vm.memory[0]; } #| First problem of day 2 sub day2a($input-filename) is export { my $program = slurp($input-filename); my $vm = IntcodeVM.new($program); # Replace bits $vm.memory[1] = 12; $vm.memory[2] = 2; $vm.run; say "Value at position 0: {$vm.output}" } sub day2b($input-filename) is export { my $program = slurp($input-filename); my $vm = IntcodeVM.new($program); for ((^100) X (^100)) -> $p { $vm.memory[1] = $p[0]; $vm.memory[2] = $p[1]; $vm.run; my $output = $vm.output; if $output == 19690720 { say "100 * noun + verb: {100 * $p[0] + $p[1]}"; last; } $vm.reset-memory; } }