with open('day7-input', 'r') as file:
  data = [l.strip('\n') for l in file]

bin_ops = {'AND': int.__and__, 'OR': int.__or__, 'RSHIFT': int.__rshift__, 'LSHIFT': int.__lshift__}

class dict_int_giver(dict):
  def __init__(self, kvs=[], readonly=None):
    super().__init__(kvs)
    self.readonly = set()
    if readonly:
      self.readonly = set(readonly)
  def __getitem__(self, key):
    try:
      return int(key.replace(',', ''))
    except ValueError:
      return dict.get(self, key, None)
  def __setitem__(self, key, value):
    if key in self.readonly:
      return
    dict.__setitem__(self, key, value)

def run_circuit(identifiers):
  queue = [line for line in data]
  while queue:
    line = queue.pop(0)
    tokens = line.split(' ')
    output = tokens[-1]
    input = tokens[:-2]
    if len(input) == 1:  # Can only be a -> b
      i = identifiers[input[0]]
      if i is not None:
        identifiers[output] = i
      else:
        queue.append(line)
    elif len(input) == 2:  # Can only be NOT a -> b. a must be identifier.
      if input[1] in identifiers:
        identifiers[output] = identifiers[input[1]] ^ 0xFFFF  # 16bit values
      else:
        queue.append(line)
    elif len(input) == 3:  # Can be any of the binary operators
      i = identifiers[input[0]]
      j = identifiers[input[2]]
      if i is not None and j is not None:
        identifiers[output] = bin_ops[input[1]](i, j) & 0xFFFF
      else:
        queue.append(line)

identifiers_1 = dict_int_giver()
run_circuit(identifiers_1)
print(identifiers_1['a'])  # Part 1
identifiers_2 = dict_int_giver([ ['b', identifiers_1['a'] ] ], ['b'])
run_circuit(identifiers_2)
print(identifiers_2['a'])  # Part 2