From a7a6b86002b595bc167af72606b14c67ed1bdf8f Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Wed, 24 Nov 2021 22:25:42 +0000 Subject: init commit --- 7/solution.py | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 7/solution.py (limited to '7/solution.py') diff --git a/7/solution.py b/7/solution.py new file mode 100644 index 0000000..77a1391 --- /dev/null +++ b/7/solution.py @@ -0,0 +1,115 @@ +from abc import abstractmethod + +class U16: + def __init__(self, value: int): + self.value = value & 0xffff + def __invert__(self): + return U16(~self.value) + def __and__(self, other): + return U16(self.value & other.value) + def __or__(self, other): + return U16(self.value | other.value) + def __rshift__(self, other): + return U16(self.value >> other.value) + def __lshift__(self, other): + return U16(self.value << other.value) + def __str__(self): + return str(self.value) + +class Node: + _value: U16 = None + @property + def value(self) -> U16: + if not self._value: + self._value = self.eval() + return self._value + def eval(self, net: dict[Node]) -> U16: + return self.eval() + @absrtactmethod + def eval(self) -> U16: + pass + +class Reference(Node): + def __init__(self, name: str): + self.name = name + def eval(self, net: dict[Node]) -> U16: + return net[self.name].value + +class Constant(Node): + def __init__(self, value): + self._value = value + +class BinaryOp(Node): + def __init__(self, left, right): + self.left = left + self.right = right + +class And(BinaryOp): + def eval(self) -> U16: + return self.left.value & self.right.value + +class Or(BinaryOp): + def eval(self) -> U16: + return self.left.value | self.right.value + +class LShift(BinaryOp): + def eval(self) -> U16: + return self.left.value << self.right.value + +class RShift(BinaryOp): + def eval(self) -> U16: + return self.left.value >> self.right.value + +class Not(Node): + def __init__(self, node): + self.node = node + def eval(self): + return ~self.node.value + +def parse_expr(net: dict[Node], expr: str) -> Node: + parts = expr.split(' ') + if len(parts) == 3: + lhs = parse_expr(net, parts[0]) + rhs = parse_expr(net, parts[2]) + if parts[1] == 'AND': + return And(lhs, rhs) + elif parts[1] == 'OR': + return Or(lhs, rhs) + elif parts[1] == 'LSHIFT': + return LShift(lhs, rhs) + elif parts[1] == 'RSHIFT': + return RShift(lhs, rhs) + elif len(parts) == 2: + if parts[0] == 'NOT': + return Not(parse_expr(net, parts[1])) + elif len(parts) == 1: + if expr.isnumeric(): + return Constant(U16(int(expr))) + if expr.isalpha(): + return Reference(net, expr) + raise ValueError(expr) + +def parse_conn(net: dict[Node], conn: str) -> tuple[str, Node]: + expr, target = conn.split(" -> ") + return target, parse_expr(net, expr) + +def part1(inp: list[str]) -> int: + net = dict() + for conn in inp: + target, node = parse_conn(net, conn) + net[target] = node + return net['a'].value + +def part2(inp: list[str]) -> int: + net = dict() + for conn in inp: + target, node = parse_conn(net, conn) + net[target] = node + net['b'] = Constant(part1(inp)) + return net['a'].value + +if __name__ == '__main__': + with open('input') as f: + inp = [line.strip() for line in f] + print(part1(inp)) + print(part2(inp)) \ No newline at end of file -- cgit v1.2.3-54-g00ecf