diff --git a/src/Year_2015/P7.py b/src/Year_2015/P7.py new file mode 100644 index 0000000..62c57bf --- /dev/null +++ b/src/Year_2015/P7.py @@ -0,0 +1,134 @@ +# --- Day 7: Some Assembly Required --- + +# This year, Santa brought little Bobby Tables a set of wires and bitwise logic +# gates! Unfortunately, little Bobby is a little under the recommended age +# range, and he needs help assembling the circuit. + +# Each wire has an identifier (some lowercase letters) and can carry a 16-bit +# signal (a number from 0 to 65535). A signal is provided to each wire by a +# gate, another wire, or some specific value. Each wire can only get a signal +# from one source, but can provide its signal to multiple destinations. A gate +# provides no signal until all of its inputs have a signal. + +# The included instructions booklet describes how to connect the parts +# together: x AND y -> z means to connect wires x and y to an AND gate, and +# then connect its output to wire z. + +# For example: + +# 123 -> x means that the signal 123 is provided to wire x. +# x AND y -> z means that the bitwise AND of wire x and wire y is provided +# to wire z. +# p LSHIFT 2 -> q means that the value from wire p is left-shifted by 2 and +# then provided to wire q. +# NOT e -> f means that the bitwise complement of the value from wire e is +# provided to wire f. + +# Other possible gates include OR (bitwise OR) and RSHIFT (right-shift). If, +# for some reason, you'd like to emulate the circuit instead, almost all +# programming languages (for example, C, JavaScript, or Python) provide +# operators for these gates. + +# For example, here is a simple circuit: + +# 123 -> x +# 456 -> y +# x AND y -> d +# x OR y -> e +# x LSHIFT 2 -> f +# y RSHIFT 2 -> g +# NOT x -> h +# NOT y -> i + +# After it is run, these are the signals on the wires: + +# d: 72 +# e: 507 +# f: 492 +# g: 114 +# h: 65412 +# i: 65079 +# x: 123 +# y: 456 + +# In little Bobby's kit's instructions booklet (provided as your puzzle input), +# what signal is ultimately provided to wire a? + +import functools + +with open("files/P7.txt") as f: + instructions = [line for line in f.read().strip().split("\n")] + + +def and_gate(x: int, y: int) -> int: + return x & y + + +def or_gate(x: int, y: int) -> int: + return x | y + + +def not_gate(x: int) -> int: + return ~x + + +def lshift_gate(x: int, y: int) -> int: + return x << y + + +def rshift_gate(x: int, y: int) -> int: + return x >> y + + +@functools.lru_cache() +def rec_solve(node): + if node.isdigit(): + return int(node) + instruction = gates[node] + if "NOT" in instruction: + return not_gate(rec_solve(instruction[1])) + elif "AND" in instruction: + return and_gate(rec_solve(instruction[0]), rec_solve(instruction[2])) + elif "OR" in instruction: + return or_gate(rec_solve(instruction[0]), rec_solve(instruction[2])) + elif "LSHIFT" in instruction: + return lshift_gate( + rec_solve(instruction[0]), rec_solve(instruction[2]) + ) + elif "RSHIFT" in instruction: + return rshift_gate( + rec_solve(instruction[0]), rec_solve(instruction[2]) + ) + else: + return rec_solve(instruction[0]) + + +gates = {} +for instr in instructions: + lhs, rhs = instr.split(" -> ") + gates[rhs.strip()] = lhs.strip().split() + + +def part_1(): + signal_a = rec_solve("a") + print(f"Signal A will be ultimately {signal_a}") + + +# --- Part Two --- + +# Now, take the signal you got on wire a, override wire b to that signal, and +# reset the other wires (including wire a). What new signal is ultimately +# provided to wire a? + + +def part_2(): + signal_a = rec_solve("a") + rec_solve.cache_clear() + gates["b"] = [str(signal_a)] + signal_b = rec_solve("a") + print(f"Signal B will be ultimately {signal_b}") + + +if __name__ == "__main__": + part_1() + part_2()