Lukas Angerer преди 2 години
родител
ревизия
471e2a48fc
променени са 13 файла, в които са добавени 372 реда и са изтрити 3 реда
  1. 19 0
      Day20/BroadcastModule.cs
  2. 33 0
      Day20/ConjunctionModule.cs
  3. 27 0
      Day20/FlipFlopModule.cs
  4. 28 0
      Day20/HiLo.cs
  5. 27 0
      Day20/Module.cs
  6. 46 3
      Day20/Parser.cs
  7. 6 0
      Day20/Program.cs
  8. 3 0
      Day20/Pulse.cs
  9. 96 0
      Day20/SignalProcessor.cs
  10. 19 0
      Day20/SinkModule.cs
  11. 58 0
      Day20/inputs/input-lar.txt
  12. 5 0
      Day20/inputs/sample1.txt
  13. 5 0
      Day20/inputs/sample2.txt

+ 19 - 0
Day20/BroadcastModule.cs

@@ -0,0 +1,19 @@
+namespace Day20;
+
+public class BroadcastModule : Module
+{
+    public BroadcastModule(string name)
+        : base(name)
+    {
+    }
+    
+    public override string GetState()
+    {
+        return string.Empty;
+    }
+
+    public override IEnumerable<Pulse> Process(Pulse p)
+    {
+        return _outputs.Select(o => new Pulse(Name, o.Name, p.Value));
+    }
+}

+ 33 - 0
Day20/ConjunctionModule.cs

@@ -0,0 +1,33 @@
+namespace Day20;
+
+public class ConjunctionModule : Module
+{
+    private readonly Dictionary<string, bool> _inputStates = new Dictionary<string, bool>();
+    
+    public ConjunctionModule(string name)
+        : base(name)
+    {
+    }
+    
+    public override string GetState()
+    {
+        return string.Concat(_inputs.Select(m => StateOf(m) ? "1" : "0"));
+    }
+
+    public override IEnumerable<Pulse> Process(Pulse p)
+    {
+        _inputStates[p.Source] = p.Value;
+        var outPulse = !AllHigh();
+        return _outputs.Select(o => new Pulse(Name, o.Name, outPulse));
+    }
+
+    private bool StateOf(Module m)
+    {
+        return _inputStates.GetValueOrDefault(m.Name, false);
+    }
+
+    private bool AllHigh()
+    {
+        return _inputs.All(StateOf);
+    }
+}

+ 27 - 0
Day20/FlipFlopModule.cs

@@ -0,0 +1,27 @@
+namespace Day20;
+
+public class FlipFlopModule : Module
+{
+    private bool _state = false;
+    
+    public FlipFlopModule(string name)
+        : base(name)
+    {
+    }
+    
+    public override string GetState()
+    {
+        return _state ? "1" : "0";
+    }
+
+    public override IEnumerable<Pulse> Process(Pulse p)
+    {
+        if (p.Value == false)
+        {
+            _state = !_state;
+            return _outputs.Select(o => new Pulse(Name, o.Name, _state));
+        }
+
+        return Enumerable.Empty<Pulse>();
+    }
+}

+ 28 - 0
Day20/HiLo.cs

@@ -0,0 +1,28 @@
+namespace Day20;
+
+public record HiLo(long High, long Low)
+{
+    public static HiLo Zero { get; } = new HiLo(0L, 0L);
+    
+    public HiLo Add(HiLo other)
+    {
+        return new HiLo(High + other.High, Low + other.Low);
+    }
+
+    public HiLo Add(Pulse p)
+    {
+        return p.Value
+            ? this with { High = High + 1 }
+            : this with { Low = Low + 1 };
+    }
+
+    public HiLo Multiply(long factor)
+    {
+        return new HiLo(factor * High, factor * Low);
+    }
+
+    public override string ToString()
+    {
+        return $"High: {High} / Low: {Low}";
+    }
+}

+ 27 - 0
Day20/Module.cs

@@ -0,0 +1,27 @@
+namespace Day20;
+
+public abstract class Module
+{
+    public string Name { get; }
+
+    protected readonly List<Module> _outputs = new List<Module>();
+    protected readonly List<Module> _inputs = new List<Module>();
+
+    protected Module(string name)
+    {
+        Name = name;
+    }
+    
+    public abstract string GetState();
+    public abstract IEnumerable<Pulse> Process(Pulse p);
+
+    public void AddOutput(Module destination)
+    {
+        _outputs.Add(destination);
+    }
+
+    public void AddInput(Module source)
+    {
+        _inputs.Add(source);
+    }
+}

+ 46 - 3
Day20/Parser.cs

@@ -4,16 +4,59 @@ namespace Day20;
 
 public partial class Parser
 {
-    [GeneratedRegex(@".*")]
+    [GeneratedRegex(@"(broadcaster|([%&-])(\w+)) -> (.*)")]
     private partial Regex LineMatch();
     
-    public void Parse(string inputFile)
+    public SignalProcessor Parse(string inputFile)
     {
         using var reader = File.OpenText(inputFile);
-        
+
+        var modules = new Dictionary<string, (Module m, string[] outputs)>();
         while (!reader.EndOfStream)
         {
             var line = reader.ReadLine()!;
+            var match = LineMatch().Match(line);
+            if (!match.Success)
+            {
+                throw new Exception($"Unable to parse line {line}");
+            }
+
+            Module? module;
+            if (match.Groups[1].Value == "broadcaster")
+            {
+                module = new BroadcastModule("broadcaster");
+                modules["broadcaster"] = (module, GetOutputs(match));
+            }
+            else
+            {
+                if (match.Groups[2].Value == "%")
+                {
+                    module = new FlipFlopModule(match.Groups[3].Value);
+                }
+                else if (match.Groups[2].Value == "&")
+                {
+                    module = new ConjunctionModule(match.Groups[3].Value);
+                }
+                else if (match.Groups[2].Value == "-")
+                {
+                    module = new SinkModule(match.Groups[3].Value);
+                }
+                else
+                {
+                    throw new Exception($"Unknown module type: {match.Groups[2].Value}");
+                }
+
+                modules[match.Groups[3].Value] = (module, GetOutputs(match));
+            }
         }
+
+        return new SignalProcessor(modules);
+    }
+
+    private static string[] GetOutputs(Match match)
+    {
+        return match.Groups[4].Value
+            .Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)
+            .ToArray();
     }
 }

+ 6 - 0
Day20/Program.cs

@@ -16,5 +16,11 @@ if (args.Length < 1)
 
 var inputFile = args[0];
 var parser = new Parser();
+var processor = parser.Parse(inputFile);
+
+var pulses = processor.Push(1000);
+Console.WriteLine();
+Console.WriteLine($"Pulses: {pulses.High} High & {pulses.Low} Low");
+Console.WriteLine($"Total: {pulses.High * pulses.Low}");
 
 return 0;

+ 3 - 0
Day20/Pulse.cs

@@ -0,0 +1,3 @@
+namespace Day20;
+
+public record Pulse(string Source, string Destination, bool Value);

+ 96 - 0
Day20/SignalProcessor.cs

@@ -0,0 +1,96 @@
+namespace Day20;
+
+public class SignalProcessor
+{
+    private readonly IDictionary<string, Module> _modules = new Dictionary<string, Module>();
+    
+    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)
+    {
+        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);
+            var hilo = PushTheButton();
+            
+            stateCounts.Add(hilo);
+            result = result.Add(hilo);
+            state = MachineState();
+            iterations++;
+        }
+
+        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()
+    {
+        var count = HiLo.Zero;
+        var queue = new Queue<Pulse>();
+        queue.Enqueue(new Pulse("button", "broadcaster", false));
+        
+        while (queue.Count > 0)
+        {
+            var pulse = queue.Dequeue();
+            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()));
+    }
+}

+ 19 - 0
Day20/SinkModule.cs

@@ -0,0 +1,19 @@
+namespace Day20;
+
+public class SinkModule : Module
+{
+    public SinkModule(string name)
+        : base(name)
+    {
+    }
+    
+    public override string GetState()
+    {
+        return string.Empty;
+    }
+
+    public override IEnumerable<Pulse> Process(Pulse p)
+    {
+        return Enumerable.Empty<Pulse>();
+    }
+}

+ 58 - 0
Day20/inputs/input-lar.txt

@@ -0,0 +1,58 @@
+%pj -> sh
+%mn -> jp
+&hf -> rg, vl, tq, qq, mv, zz
+%xl -> hf
+%sv -> mn, dl
+%kk -> lh
+&sj -> kz
+%jj -> lq, kk
+%mr -> bm, hb
+%sx -> lq, fn
+%fn -> zr, lq
+%pf -> dl, gv
+%lr -> jj, lq
+%jp -> dl, pj
+&hb -> sj, mr, rz, qg, pr
+%vg -> zz, hf
+%pr -> zq
+%hn -> pf
+%jg -> tj
+%qg -> vk
+%dv -> xl, hf
+&qq -> kz
+%fm -> lr
+&ls -> kz
+%pd -> hb, xg
+%rj -> hb
+%fb -> hf, tq
+%zz -> np
+%bm -> pd, hb
+%xn -> lq, fm
+%gv -> jg, dl
+%dz -> sx
+%zs -> dl, nh
+%tj -> zs, dl
+%mv -> vl
+&kz -> rx
+%np -> cl, hf
+&bg -> kz
+%vl -> vg
+%xg -> rz, hb
+%rz -> pr
+%zq -> hb, qg
+%lh -> rd
+%zr -> lq
+%fl -> hb, rj
+%xr -> xn, lq
+%rd -> dz, lq
+%cl -> hf, gj
+%nh -> dl
+%sh -> hn, dl
+%vk -> fx, hb
+%gj -> hf, dv
+%tq -> mv
+&dl -> hn, pj, ls, mn, jg, sv
+%fx -> fl, hb
+&lq -> bg, kk, dz, xr, lh, fm
+%rg -> hf, fb
+broadcaster -> xr, mr, rg, sv

+ 5 - 0
Day20/inputs/sample1.txt

@@ -0,0 +1,5 @@
+broadcaster -> a, b, c
+%a -> b
+%b -> c
+%c -> inv
+&inv -> a

+ 5 - 0
Day20/inputs/sample2.txt

@@ -0,0 +1,5 @@
+broadcaster -> a
+%a -> inv, con
+&inv -> b
+%b -> con
+&con -> output