Forráskód Böngészése

Day 20 part 2 - blind guessing to track cycles

Lukas Angerer 2 éve
szülő
commit
87265cbe26

+ 5 - 0
Day20/ConjunctionModule.cs

@@ -20,6 +20,11 @@ public class ConjunctionModule : Module
         var outPulse = !AllHigh();
         return _outputs.Select(o => new Pulse(Name, o.Name, outPulse));
     }
+    
+    public override void Reset()
+    {
+        _inputStates.Clear();
+    }
 
     private bool StateOf(Module m)
     {

+ 5 - 0
Day20/FlipFlopModule.cs

@@ -14,6 +14,11 @@ public class FlipFlopModule : Module
         return _state ? "1" : "0";
     }
 
+    public override void Reset()
+    {
+        _state = false;
+    }
+
     public override IEnumerable<Pulse> Process(Pulse p)
     {
         if (p.Value == false)

+ 4 - 0
Day20/Module.cs

@@ -7,6 +7,8 @@ public abstract class Module
     protected readonly List<Module> _outputs = new List<Module>();
     protected readonly List<Module> _inputs = new List<Module>();
 
+    public IEnumerable<Module> Inputs => _inputs;
+
     protected Module(string name)
     {
         Name = name;
@@ -15,6 +17,8 @@ public abstract class Module
     public abstract string GetState();
     public abstract IEnumerable<Pulse> Process(Pulse p);
 
+    public virtual void Reset() {}
+
     public void AddOutput(Module destination)
     {
         _outputs.Add(destination);

+ 20 - 0
Day20/Primes.cs

@@ -0,0 +1,20 @@
+namespace Day20;
+
+public static class Primes
+{
+    public static IEnumerable<long> Factorize(long num)
+    {
+        var remainder = num;
+        for (var c = 2; c < remainder / 2; c++)
+        {
+            if (remainder % c == 0)
+            {
+                yield return c;
+                remainder /= c;
+                c = 2;
+            }
+        }
+
+        yield return remainder;
+    }
+}

+ 5 - 1
Day20/Program.cs

@@ -20,7 +20,11 @@ var processor = parser.Parse(inputFile);
 
 var pulses = processor.Push(1000);
 Console.WriteLine();
-Console.WriteLine($"Pulses: {pulses.High} High & {pulses.Low} Low");
+//Console.WriteLine($"Pulses: {pulses.High} High & {pulses.Low} Low");
 Console.WriteLine($"Total: {pulses.High * pulses.Low}");
 
+var count = processor.WaitFor("rx");
+Console.WriteLine();
+Console.WriteLine($"First 'rx' @ {count}");
+
 return 0;

+ 56 - 6
Day20/SignalProcessor.cs

@@ -2,7 +2,10 @@
 
 public class SignalProcessor
 {
-    private readonly IDictionary<string, Module> _modules = new Dictionary<string, Module>();
+    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)
     {
@@ -30,6 +33,7 @@ public class SignalProcessor
 
     public HiLo Push(int count)
     {
+        Reset();
         var visited = new HashSet<string>();
         var stateCounts = new List<HiLo>();
         var state = MachineState();
@@ -38,14 +42,14 @@ public class SignalProcessor
 
         while (!visited.Contains(state) && iterations < count)
         {
-            Console.WriteLine(state);
+            //Console.WriteLine(state);
             visited.Add(state);
-            var hilo = PushTheButton();
+            iterations++;
+            var hilo = PushTheButton(iterations);
             
             stateCounts.Add(hilo);
             result = result.Add(hilo);
             state = MachineState();
-            iterations++;
         }
 
         if (iterations == 0)
@@ -68,7 +72,7 @@ public class SignalProcessor
         return result;
     }
 
-    public HiLo PushTheButton()
+    public HiLo PushTheButton(int iteration)
     {
         var count = HiLo.Zero;
         var queue = new Queue<Pulse>();
@@ -77,7 +81,12 @@ public class SignalProcessor
         while (queue.Count > 0)
         {
             var pulse = queue.Dequeue();
-            Console.WriteLine($"Sending {pulse.Value} from {pulse.Source} to {pulse.Destination}");
+            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))
@@ -93,4 +102,45 @@ public class SignalProcessor
     {
         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();
+        }
+    }
 }