diff --git a/adventofcode/2015/day7/day7.py b/adventofcode/2015/day7/day7.py new file mode 100644 index 0000000..0008ea0 --- /dev/null +++ b/adventofcode/2015/day7/day7.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +import fileinput + + +def parse_circuit(inp): + instructions = {} + # dst: (OP, ARGS) + for line in inp: + op, dst = line.split(" -> ") + op = op.split(" ") + if len(op) == 1: # ASSIGN + src = op[0] + instructions[dst] = ("ASSIGN", src) + elif len(op) == 2: # NOT + assert op[0] == "NOT" + instructions[dst] = ("NOT", op[1]) + elif len(op) == 3: # BINARY OP + instructions[dst] = (op[1], (op[0], op[2])) + return instructions + + +def main(inp): + instructions = parse_circuit(inp) + res = evaluate_instruction("a", instructions) + print("Part 1: ", res) + instructions["b"] = ("ASSIGN", str(res)) + res = evaluate_instruction("a", instructions, state={}) # reset state + print("Part 2: ", res) + + +def evaluate_instruction(start_wire, instructions, state={}): + if start_wire in state: + return state[start_wire] + + op, args = instructions[start_wire] + result = -1 + if op == "ASSIGN": + if args.isdigit(): + result = int(args) + else: + result = evaluate_instruction(args, instructions, state) + elif op == "NOT": + if args.isdigit(): + result = 65535 - int(args) + else: + result = 65535 - evaluate_instruction(args, instructions, state) + elif op in ["AND", "OR", "LSHIFT", "RSHIFT"]: + left, right = args + if left.isdigit(): + left = int(left) + else: + left = evaluate_instruction(left, instructions, state) + if right.isdigit(): + right = int(right) + else: + right = evaluate_instruction(right, instructions, state) + match op: + case "OR": + result = left | right + case "AND": + result = left & right + case "LSHIFT": + result = left << right + case "RSHIFT": + result = left >> right + case _: + assert False, "Unreachable" + else: + assert False, "Unreachable" + + state[start_wire] = result + return result + + +if __name__ == "__main__": + lines = [x.rstrip() for x in fileinput.input()] + main(lines)