102 lines
2.5 KiB
Python
102 lines
2.5 KiB
Python
import logging
|
|
import operator
|
|
import os
|
|
import sys
|
|
from typing import Callable
|
|
|
|
VERBOSE = os.getenv("AOC_VERBOSE") == "True"
|
|
logging.basicConfig(level=logging.INFO if VERBOSE else logging.WARNING)
|
|
|
|
OPERATORS = {
|
|
"AND": operator.and_,
|
|
"OR": operator.or_,
|
|
"LSHIFT": operator.lshift,
|
|
"RSHIFT": operator.rshift,
|
|
}
|
|
|
|
ValueGetter = Callable[[dict[str, int]], int]
|
|
Signals = dict[
|
|
str,
|
|
tuple[
|
|
tuple[str, str],
|
|
tuple[ValueGetter, ValueGetter],
|
|
Callable[[int, int], int],
|
|
],
|
|
]
|
|
|
|
|
|
def zero_op(_a: int, _b: int) -> int:
|
|
return 0
|
|
|
|
|
|
def value_of(key: str) -> tuple[str, Callable[[dict[str, int]], int]]:
|
|
try:
|
|
return "", lambda _p, _v=int(key): _v
|
|
except ValueError:
|
|
return key, lambda values: values[key]
|
|
|
|
|
|
lines = sys.stdin.read().splitlines()
|
|
|
|
signals: Signals = {}
|
|
values: dict[str, int] = {"": 0}
|
|
|
|
for line in lines:
|
|
command, signal = line.split(" -> ")
|
|
|
|
if command.startswith("NOT"):
|
|
name = command.split(" ")[1]
|
|
signals[signal] = (
|
|
(name, ""),
|
|
(lambda values, _n=name: values[_n], lambda _v: 0),
|
|
lambda a, _b: ~a,
|
|
)
|
|
|
|
elif not any(command.find(name) >= 0 for name in OPERATORS):
|
|
try:
|
|
values[signal] = int(command)
|
|
except ValueError:
|
|
signals[signal] = (
|
|
(command, ""),
|
|
(lambda values, _c=command: values[_c], lambda _v: 0),
|
|
lambda a, _b: a,
|
|
)
|
|
|
|
else:
|
|
op: Callable[[int, int], int] = zero_op
|
|
lhs_s, rhs_s = "", ""
|
|
|
|
for name in OPERATORS:
|
|
if command.find(name) >= 0:
|
|
op = OPERATORS[name]
|
|
lhs_s, rhs_s = command.split(f" {name} ")
|
|
break
|
|
|
|
lhs_s, lhs_fn = value_of(lhs_s)
|
|
rhs_s, rhs_fn = value_of(rhs_s)
|
|
|
|
signals[signal] = ((lhs_s, rhs_s), (lhs_fn, rhs_fn), op)
|
|
|
|
|
|
def process(
|
|
signals: Signals,
|
|
values: dict[str, int],
|
|
) -> dict[str, int]:
|
|
while signals:
|
|
signal = next(s for s in signals if all(p in values for p in signals[s][0]))
|
|
_, deps, command = signals[signal]
|
|
values[signal] = command(deps[0](values), deps[1](values)) % 65536
|
|
del signals[signal]
|
|
|
|
return values
|
|
|
|
|
|
values_1 = process(signals.copy(), values.copy())
|
|
logging.info("\n" + "\n".join(f"{k}: {values_1[k]}" for k in sorted(values_1)))
|
|
answer_1 = values_1["a"]
|
|
print(f"answer 1 is {answer_1}")
|
|
|
|
values_2 = process(signals.copy(), values | {"b": values_1["a"]})
|
|
answer_2 = values_2["a"]
|
|
print(f"answer 2 is {answer_2}")
|