| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- namespace Day20;
- public class SignalProcessor
- {
- private readonly Dictionary<string, Module> _modules = new Dictionary<string, Module>();
- private HashSet<string> _trackCycles = new HashSet<string>();
- private Dictionary<string, List<long>> _cycleLengths = new Dictionary<string, List<long>>();
-
- public SignalProcessor(Dictionary<string, (Module m, string[] outputs)> modules)
- {
- foreach (var kvp in modules)
- {
- _modules[kvp.Key] = kvp.Value.m;
- foreach (var o in kvp.Value.outputs)
- {
- Module? dst;
- if (modules.TryGetValue(o, out var t))
- {
- dst = modules[o].m;
- }
- else
- {
- _modules.TryAdd(o, new SinkModule(o));
- dst = _modules[o];
- }
-
- kvp.Value.m.AddOutput(dst);
- dst.AddInput(kvp.Value.m);
- }
- }
- }
- public HiLo Push(int count)
- {
- Reset();
- var visited = new HashSet<string>();
- var stateCounts = new List<HiLo>();
- var state = MachineState();
- var iterations = 0;
- var result = HiLo.Zero;
- while (!visited.Contains(state) && iterations < count)
- {
- //Console.WriteLine(state);
- visited.Add(state);
- iterations++;
- var hilo = PushTheButton(iterations);
-
- stateCounts.Add(hilo);
- result = result.Add(hilo);
- state = MachineState();
- }
- if (iterations == 0)
- {
- throw new InvalidOperationException("WTF?");
- }
- if (iterations < count)
- {
- Console.WriteLine($"Cycle @ {iterations} with state {state}");
- var cycles = count / iterations;
- result = result.Multiply(cycles);
- var remainder = count % iterations;
- for (var i = 0; i < remainder; i++)
- {
- result = result.Add(stateCounts[i]);
- }
- }
- return result;
- }
- public HiLo PushTheButton(int iteration)
- {
- var count = HiLo.Zero;
- var queue = new Queue<Pulse>();
- queue.Enqueue(new Pulse("button", "broadcaster", false));
-
- while (queue.Count > 0)
- {
- var pulse = queue.Dequeue();
- if (_trackCycles.Contains(pulse.Source) && pulse.Value)
- {
- _cycleLengths.TryAdd(pulse.Source, new List<long>());
- _cycleLengths[pulse.Source].Add(iteration);
- }
- //Console.WriteLine($"Sending {pulse.Value} from {pulse.Source} to {pulse.Destination}");
- var dst = _modules[pulse.Destination];
- count = count.Add(pulse);
- foreach (var outPulse in dst.Process(pulse))
- {
- queue.Enqueue(outPulse);
- }
- }
-
- return count;
- }
- private string MachineState()
- {
- return string.Join("|", _modules.Select(kvp => kvp.Value.GetState()));
- }
- public long WaitFor(string sentry)
- {
- Reset();
- var iterations = 0;
- var sentryInputs = _modules[sentry].Inputs.Single().Inputs.Select(m => m.Name).ToList();
- _trackCycles = new HashSet<string>(sentryInputs);
- _cycleLengths = new Dictionary<string, List<long>>();
- while (iterations < 100000)
- {
- iterations++;
- PushTheButton(iterations);
- }
- var lcmFactors = new HashSet<long>();
- foreach (var kvp in _cycleLengths)
- {
- var first = kvp.Value.First();
- if (kvp.Value.Any(x => x % first != 0))
- {
- throw new Exception($"Mismatching cycle '{kvp.Key}' => {string.Join("\n", kvp.Value)}");
- }
- foreach (var prime in Primes.Factorize(first))
- {
- lcmFactors.Add(prime);
- }
- }
-
- var lcm = lcmFactors.Aggregate(1L, (acc, item) => acc * item);
- return lcm;
- }
- private void Reset()
- {
- foreach (var kvp in _modules)
- {
- kvp.Value.Reset();
- }
- }
- }
|