20_pulse.py 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. #!/usr/bin/env python3
  2. import sys
  3. from collections import deque
  4. from itertools import count
  5. from math import lcm
  6. def parse(inp):
  7. graph = {}
  8. for line in inp:
  9. src, dst = line.rstrip().split(' -> ')
  10. outputs = dst.split(', ')
  11. ty = src[0]
  12. if ty in '%&':
  13. src = src[1:]
  14. prev = graph.get(src, (None, [], None))[1]
  15. graph[src] = ty, prev, outputs
  16. for out in outputs:
  17. graph.setdefault(out, (None, [], []))[1].append(src)
  18. return graph
  19. def pulse(graph, flipflops, conjunctions):
  20. work = deque([('button', 'broadcaster', False)])
  21. while work:
  22. prev, node, high = work.popleft()
  23. yield node, high
  24. ty, inputs, outputs = graph[node]
  25. if ty == '%':
  26. if not high:
  27. flipflops[node] = out = not flipflops.get(node, False)
  28. work.extend((node, output, out) for output in outputs)
  29. elif ty == '&':
  30. state = conjunctions.setdefault(node, {i: False for i in inputs})
  31. state[prev] = high
  32. out = not all(state.values())
  33. work.extend((node, output, out) for output in outputs)
  34. else:
  35. work.extend((node, output, high) for output in outputs)
  36. def low_high_counts(graph, times):
  37. flipflops = {}
  38. conjunctions = {}
  39. counts = [0, 0]
  40. for _ in range(times):
  41. for _, high in pulse(graph, flipflops, conjunctions):
  42. counts[high] += 1
  43. return counts[0] * counts[1]
  44. def pulse_until_rx(graph):
  45. flipflops = {}
  46. conjunctions = {}
  47. sync_nodes = graph[graph['rx'][1][0]][1]
  48. periods = {}
  49. for presses in count(1):
  50. for node, high in pulse(graph, flipflops, conjunctions):
  51. if not high and node in sync_nodes:
  52. periods[node] = presses
  53. if len(periods) == len(sync_nodes):
  54. return lcm(*periods.values())
  55. graph = parse(sys.stdin)
  56. print(low_high_counts(graph, 1000))
  57. print(pulse_until_rx(graph))