Today’s challenge describes a simple instruction set for a CPU, incrementing and decrementing values in registers according to simple conditions. We have to interpret a stream of these instructions, and to prove that we’ve done so, give the highest value of any register, both at the end of the program and throughout the whole program.
This turned out to be a nice straightforward one to implement, as the instruction format was easily parsed by regular expression, and Python provides the
eval function which made evaluating the conditions a doddle.
Import various standard library bits that we’ll use later.
import re import fileinput as fi from math import inf from collections import defaultdict
We could just parse the instructions by splitting the string, but using a regular expression is a little bit more robust because it won’t match at all if given an invalid instruction.
INSTRUCTION_RE = re.compile(r'(\w+) (inc|dec) (-?\d+) if (.+)\s*') def parse_instruction(instruction): match = INSTRUCTION_RE.match(instruction) return match.group(1, 2, 3, 4)
Executing an instruction simply checks the condition and if it evaluates to
True updates the relevant register.
def exec_instruction(registers, instruction): name, op, value, cond = instruction value = int(value) if op == 'dec': value = -value if eval(cond, globals(), registers): registers[name] += value
highest_value returns the maximum value found in any register.
def highest_value(registers): return sorted(registers.items(), key=lambda x: x, reverse=True)
Finally, loop through all the instructions and carry them out, updating
global_max as we go. We need to be able to deal with registers that haven’t been accessed before. Keeping the registers in a dictionary means that we can evaluate the conditions directly using
eval above, passing it as the
locals argument. The standard
dict will raise an exception if we try to access a key that doesn’t exist, so instead we use
collections.defaultdict, which allows us to specify what the default value for a non-existent key will be. New registers start at 0, so we use a simple lambda to define a function that always returns 0.
global_max = -inf registers = defaultdict(lambda: 0) for i in map(parse_instruction, fi.input()): exec_instruction(registers, i) global_max = max(global_max, highest_value(registers)) print('Max value:', highest_value(registers)) print('All-time max:', global_max)