On Day 12 we can implement virtual machine executing assembunny code. Our virtual machine can execute only four instructions:
cpy x y
copies x (either an integer or the value of a register) into register y.inc x
increases the value of register x by one.dec x
decreases the value of register x by one.jnz x y
jumps to an instruction y away (positive means forward; negative means backward), but only if x is not zero.It also has four registers a, b, c and d, all of them initialized with value 0. Our input is a program that looks like this:
cpy 41 a
inc a
inc a
dec a
jnz a 2
dec a
Our task is to return the value of register a after executing such program.
Here is my solution:
data = File.readlines("12.txt", chomp: true).map(&:strip)
registers = { "a" => 0, "b" => 0, "c" => 0, "d" => 0 }
pc = 0
def render(data, pc, registers)
$stdout.clear_screen
data.each_with_index do |line, index|
puts [index == pc ? "=> " : " ", index.to_s.rjust(2), line].join(" ")
end
puts "A = #{registers["a"]}, B = #{registers["b"]}, C = #{registers["c"]}, D = #{registers["d"]}, PC = #{pc}"
end
while pc < data.size
line = data[pc]
jump = false
if line =~ /cpy (-?\d+) ([a-d])/
value = Regexp.last_match[1].to_i
register = Regexp.last_match[2]
registers[register] = value
elsif line =~ /cpy ([a-d]) ([a-d])/
source_register = Regexp.last_match[1]
target_register = Regexp.last_match[2]
registers[target_register] = registers[source_register]
elsif line =~ /inc ([a-d])/
register = Regexp.last_match[1]
registers[register] += 1
elsif line =~ /dec ([a-d])/
register = Regexp.last_match[1]
registers[register] -= 1
elsif line =~ /jnz (-?\d+) (-?\d+)/
value = Regexp.last_match[1].to_i
offset = Regexp.last_match[2].to_i
if value != 0
pc += offset
jump = true
end
elsif line =~ /jnz ([a-d]) (-?\d+)/
register = Regexp.last_match[1]
offset = Regexp.last_match[2].to_i
if registers[register] != 0
pc += offset
jump = true
end
end
pc += 1 unless jump
end
puts registers.inspect
There is nothing fancy here. I have @registers
hash that keeps track of register values, @pc
which is program counter pointing to the current line of code. Then there is a loop executing each instruction of our program.
Nothing new here, the only change is that register c is initialized with value 1. It takes a lot more to execute this code then.