SignalProcessor.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. namespace Day20;
  2. public class SignalProcessor
  3. {
  4. private readonly Dictionary<string, Module> _modules = new Dictionary<string, Module>();
  5. private HashSet<string> _trackCycles = new HashSet<string>();
  6. private Dictionary<string, List<long>> _cycleLengths = new Dictionary<string, List<long>>();
  7. public SignalProcessor(Dictionary<string, (Module m, string[] outputs)> modules)
  8. {
  9. foreach (var kvp in modules)
  10. {
  11. _modules[kvp.Key] = kvp.Value.m;
  12. foreach (var o in kvp.Value.outputs)
  13. {
  14. Module? dst;
  15. if (modules.TryGetValue(o, out var t))
  16. {
  17. dst = modules[o].m;
  18. }
  19. else
  20. {
  21. _modules.TryAdd(o, new SinkModule(o));
  22. dst = _modules[o];
  23. }
  24. kvp.Value.m.AddOutput(dst);
  25. dst.AddInput(kvp.Value.m);
  26. }
  27. }
  28. }
  29. public HiLo Push(int count)
  30. {
  31. Reset();
  32. var visited = new HashSet<string>();
  33. var stateCounts = new List<HiLo>();
  34. var state = MachineState();
  35. var iterations = 0;
  36. var result = HiLo.Zero;
  37. while (!visited.Contains(state) && iterations < count)
  38. {
  39. //Console.WriteLine(state);
  40. visited.Add(state);
  41. iterations++;
  42. var hilo = PushTheButton(iterations);
  43. stateCounts.Add(hilo);
  44. result = result.Add(hilo);
  45. state = MachineState();
  46. }
  47. if (iterations == 0)
  48. {
  49. throw new InvalidOperationException("WTF?");
  50. }
  51. if (iterations < count)
  52. {
  53. Console.WriteLine($"Cycle @ {iterations} with state {state}");
  54. var cycles = count / iterations;
  55. result = result.Multiply(cycles);
  56. var remainder = count % iterations;
  57. for (var i = 0; i < remainder; i++)
  58. {
  59. result = result.Add(stateCounts[i]);
  60. }
  61. }
  62. return result;
  63. }
  64. public HiLo PushTheButton(int iteration)
  65. {
  66. var count = HiLo.Zero;
  67. var queue = new Queue<Pulse>();
  68. queue.Enqueue(new Pulse("button", "broadcaster", false));
  69. while (queue.Count > 0)
  70. {
  71. var pulse = queue.Dequeue();
  72. if (_trackCycles.Contains(pulse.Source) && pulse.Value)
  73. {
  74. _cycleLengths.TryAdd(pulse.Source, new List<long>());
  75. _cycleLengths[pulse.Source].Add(iteration);
  76. }
  77. //Console.WriteLine($"Sending {pulse.Value} from {pulse.Source} to {pulse.Destination}");
  78. var dst = _modules[pulse.Destination];
  79. count = count.Add(pulse);
  80. foreach (var outPulse in dst.Process(pulse))
  81. {
  82. queue.Enqueue(outPulse);
  83. }
  84. }
  85. return count;
  86. }
  87. private string MachineState()
  88. {
  89. return string.Join("|", _modules.Select(kvp => kvp.Value.GetState()));
  90. }
  91. public long WaitFor(string sentry)
  92. {
  93. Reset();
  94. var iterations = 0;
  95. var sentryInputs = _modules[sentry].Inputs.Single().Inputs.Select(m => m.Name).ToList();
  96. _trackCycles = new HashSet<string>(sentryInputs);
  97. _cycleLengths = new Dictionary<string, List<long>>();
  98. while (iterations < 100000)
  99. {
  100. iterations++;
  101. PushTheButton(iterations);
  102. }
  103. var lcmFactors = new HashSet<long>();
  104. foreach (var kvp in _cycleLengths)
  105. {
  106. var first = kvp.Value.First();
  107. if (kvp.Value.Any(x => x % first != 0))
  108. {
  109. throw new Exception($"Mismatching cycle '{kvp.Key}' => {string.Join("\n", kvp.Value)}");
  110. }
  111. foreach (var prime in Primes.Factorize(first))
  112. {
  113. lcmFactors.Add(prime);
  114. }
  115. }
  116. var lcm = lcmFactors.Aggregate(1L, (acc, item) => acc * item);
  117. return lcm;
  118. }
  119. private void Reset()
  120. {
  121. foreach (var kvp in _modules)
  122. {
  123. kvp.Value.Reset();
  124. }
  125. }
  126. }