Advent of Code 2017, Day 8: I Heard You Like Registers

#ruby #advent of code 2017

Part A

On Day 8 we need to implement simple CPU performing two instructions on registers. They look like this:

b inc 5 if a > 1
a inc 1 if b < 5
c dec -10 if a >= 1
c inc -20 if c == 10

We have register, operation type, amount and condition. Our task is to tell what is the largest value in any register.

data = File.readlines("8.txt", chomp: true)
assignments = []
operations = []
variables = []

data.each do |line|
  match = line.match(/\A([a-z]+) (inc|dec) (-?\d+) (.+)\z/)
  name = match[1]
  op = match[2]
  value = match[3]
  condition = match[4]

  variables.push(name)
  assignments.push("#{name} = 0")

  if op == "inc"
    operations.push("#{name} += #{value} #{condition}")
  else
    operations.push("#{name} -= #{value} #{condition}")
  end
end

code = (assignments + operations).join("\n")
code += "\nputs [#{variables.join(", ")}].max"
eval(code)

We can use Ruby eval for that to save on code for parsing conditions. The above code is parsing our input and builds assignments and increase/decrease operations. At the end we add one more line to display the maximum value from all registers.

For the example code we will build the following Ruby code:

b = 0
a = 0
c = 0
c = 0
b += 5 if a > 1
a += 1 if b < 5
c -= -10 if a >= 1
c += -20 if c == 10
puts [b, a, c, c].max

Part B

In the second part we need to tell what is the highest value every held in any register, not at the end of the program.

We need to slighly modify solution from the first part.

data = File.readlines("8.txt", chomp: true)
assignments = []
operations = []
variables = []

data.each do |line|
  match = line.match(/\A([a-z]+) (inc|dec) (-?\d+) (.+)\z/)
  name = match[1]
  op = match[2]
  value = match[3]
  condition = match[4]

  variables.push(name)
  assignments.push("#{name} = 0")

  if op == "inc"
    operations.push("#{name} += #{value} #{condition}")
  else
    operations.push("#{name} -= #{value} #{condition}")
  end

  operations.push("max = #{name} if #{name} > max")
end

code = ["max = -Float::INFINITY"]
code += assignments
code += operations
code += ["puts max"]

code = code.join("\n")
eval(code)

We added additional line to our code, to store current maximum value. Now generated code for eval will look like this:

max = -Float::INFINITY
b = 0
a = 0
c = 0
c = 0
b += 5 if a > 1
max = b if b > max
a += 1 if b < 5
max = a if a > max
c -= -10 if a >= 1
max = c if c > max
c += -20 if c == 10
max = c if c > max
puts max