I'm currently using the Advent of Code programming challenges as an opportunity to learn some python. The following code is my solution for the Day 8 challenge, where the task is to write a programm that reads a set of instructions which are then performed on registers. Registers start with a value of 0. Each instruction may increase or decrease the value of a register. The programm should return the maximum value in any register at the end of execution as well as the maximum that any register had during the whole process.
An instructions looks as follows: <register> <operation> <integer> if <register> <boolop> <integer>. Where register is a name of a register, operation is either inc to increase the value of a register, or dec to decrease its value. boolop is a comparison operator. The instruction should only be executed if the condition is true, e.g. a inc 10 if b < 0 will increase the value of the register a by 10 if the current value for register b is less than 0.
I read the input from a file called in. An example input can be found here. The expected output for this input would be (2971, 4254).
import re def is_int(str): if str == '': return False if str[0] in ('+', '-'): return str[1:].isdecimal() return str.isdecimal() def value(registers, val): if is_int(val): return int(val) if not val in registers: registers[val] = 0 return registers[val] def max_register(registers): return max([x for _, x in registers.items()]) class Operation: def __init__(self, line): res = re.search('([^ ]*) ([^ ]*) ([^ ]*)', line) self.left = res.group(1) self.operator = res.group(2) self.right = res.group(3) def __repr__(self): return self.left + ' ' + self.operator + ' ' + self.right def perform(self, registers): l, r = value(registers, self.left), value(registers, self.right) if self.operator == 'inc': registers[self.left] = l + r elif self.operator == 'dec': registers[self.left] = l - r else: print('Unsupported operation', self.operator) class Condition: def __init__(self, line): res = re.search('if ([^ ]*) ([^ ]*) ([^ ]*)', line) self.left = res.group(1) self.operator = res.group(2) self.right = res.group(3) def __repr__(self): return self.left + ' ' + self.operator + ' ' + self.right def test(self, registers): l, r = (value(registers, self.left), value(registers, self.right)) if self.operator == '==': return l == r elif self.operator == '!=': return l != r if self.operator == '>': return l > r elif self.operator == '>=': return l >= r elif self.operator == '<': return l < r elif self.operator == '<=': return l <= r else: print('Unsupported condition operator', self.operator) return False class Instruction: def __init__(self, line): res = re.search('(.*) (if .*)', line) self.operation = Operation(res.group(1)) self.condition = Condition(res.group(2)) def __repr__(self): return str(self.operation) + ' ' + str(self.condition) def perform(self, registers): if self.condition.test((registers)): self.operation.perform(registers) class Programm: def __init__(self, instr): self.instructions = instr self.position = 0 def __repr__(self): return '@' + self.position + '\n' + str(self.instructions) def run_next(self, registers): if self.position >= len(self.instructions): return False self.instructions[self.position].perform(registers) self.position = self.position + 1 return True def run(self, registers): for _ in range(len(self.instructions)): self.run_next(registers) def parse_programm(file): lines = file.read().splitlines() return Programm([Instruction(i) for i in lines]) def run(input): with open(input) as infile: programm = parse_programm(infile) registers = {} curmax = 0 while programm.run_next(registers): curmax = max(curmax, max_register(registers)) return (max_register(registers), curmax) if __name__ == '__main__': print(run("in")) I am especially interested in whether the code is pythonic and how it could be improved. E.g. the use of regexes to parse the instructions feels kinda hacky.
is_intfunction is pointless (just cast toint); and it doesn't make sense to usere.searchoverre.match; and probably a bunch of other stuff. \$\endgroup\$is_intfunction was so simplify the usage ofvalue(). I wanted a function where I can input astringor andintand getting back the value of the register matching thestringor theintvalue itself. \$\endgroup\$is_int(x)would returnTruefor values ofxthat were not ints, but rather, register names? That sounds like your current code is redundant but your future code is actively confusing! \$\endgroup\$value(int)will return the value, butvalue(string)will return the current value of the register with this name. Theis_intfunction is just a helper to distinguish between those too cases invalue()and will of course only returnTrue, wenn thexis anint. \$\endgroup\$