Procházet zdrojové kódy

Day 8 part 2 with prime factorization

Lukas Angerer před 2 roky
rodič
revize
e7c0ffb2f4
6 změnil soubory, kde provedl 89 přidání a 23 odebrání
  1. 2 0
      Day8/INode.cs
  2. 44 22
      Day8/MapData.cs
  3. 4 0
      Day8/Node.cs
  4. 1 1
      Day8/Parser.cs
  5. 20 0
      Day8/Primes.cs
  6. 18 0
      Day8/Program.cs

+ 2 - 0
Day8/INode.cs

@@ -5,4 +5,6 @@ public interface INode
     string Name { get; }
     Node? Left { get; }
     Node? Right { get; }
+    bool IsStart { get; }
+    bool IsEnd { get; }
 }

+ 44 - 22
Day8/MapData.cs

@@ -3,43 +3,65 @@
 public class MapData
 {
     public string Instructions { get; }
-    public Node Start { get; }
+    public IList<Node> Nodes { get; }
 
-    public MapData(string instructions, Node start)
+    public MapData(string instructions, IList<Node> nodes)
     {
         Instructions = instructions;
-        Start = start;
+        Nodes = nodes;
     }
 
     public long Walk()
     {
-        var current = Start;
+        var current = Nodes.First(n => n.IsStart);
         var steps = 0L;
 
-        while (current.Name != "ZZZ")
+        while (!current.IsEnd)
         {
-            if (steps >= 1000000)
-            {
-                throw new Exception("Over ONE MILLION");
-            }
-            
-            var instruction = Instructions[(int)(steps % Instructions.Length)];
-            if (instruction != 'L' && instruction != 'R')
-            {
-                throw new Exception($"Unknown instruction: {instruction} @ {steps}");
-            }
-            
-            Console.WriteLine($"{current.Name} => {instruction}");
-            
+            current = Move(steps, current);
             steps++;
-            current = instruction == 'L' ? current.Left : current.Right;
+        }
+
+        return steps;
+    }
+
+    public long[] MultiWalk()
+    {
+        var starts = Nodes.Where(n => n.Name.Last() == 'A').ToArray();
+        var cycleLengths = new List<long>();
+
+        foreach (var node in starts)
+        {
+            var current = node;
+            var steps = 0;
             
-            if (current == null)
+            while (!current.IsEnd)
             {
-                throw new Exception($"Ended in null after: {instruction} @ {steps}");
+                current = Move(steps, current);
+                steps++;
             }
+            
+            cycleLengths.Add(steps);
+            Console.WriteLine(string.Join(", ", cycleLengths));
         }
 
-        return steps;
+        return cycleLengths.ToArray();
+    }
+
+    private Node Move(long step, Node node)
+    {
+        if (step >= 10000000)
+        {
+            throw new Exception("Over TEN MILLION");
+        }
+        
+        var instruction = Instructions[(int)(step % Instructions.Length)];
+        if (instruction != 'L' && instruction != 'R')
+        {
+            throw new Exception($"Unknown instruction: {instruction} @ {step}");
+        }
+        
+        return (instruction == 'L' ? node.Left : node.Right)
+            ?? throw new Exception($"Ended in null after: {instruction} @ {step}");
     }
 }

+ 4 - 0
Day8/Node.cs

@@ -5,9 +5,13 @@ public class Node : INode
     public string Name { get; }
     public Node? Left { get; set; }
     public Node? Right { get; set; }
+    public bool IsStart { get; }
+    public bool IsEnd { get; }
 
     public Node(string name)
     {
         Name = name;
+        IsStart = Name.Last() == 'A';
+        IsEnd = Name.Last() == 'Z';
     }
 }

+ 1 - 1
Day8/Parser.cs

@@ -35,7 +35,7 @@ public partial class Parser
             throw new Exception($"Cannot find start node");
         }
 
-        return new MapData(instructions, start);
+        return new MapData(instructions, nodeMap.Values.ToList());
     }
 
     private Node GetNode(Dictionary<string, Node> nodeMap, string nodeName)

+ 20 - 0
Day8/Primes.cs

@@ -0,0 +1,20 @@
+namespace Day8;
+
+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;
+    }
+}

+ 18 - 0
Day8/Program.cs

@@ -22,4 +22,22 @@ var steps = mapData.Walk();
 Console.WriteLine();
 Console.WriteLine($"Steps: {steps}");
 
+Console.WriteLine();
+
+var cycles = mapData.MultiWalk();
+Console.WriteLine();
+
+var factors = new HashSet<long>();
+foreach (var cycle in cycles)
+{
+    var cycleFactors = Primes.Factorize(cycle).ToList();
+    Console.WriteLine($"{cycle} => {string.Join(" * ", cycleFactors)}");
+    foreach (var f in cycleFactors)
+    {
+        factors.Add(f);
+    }
+}
+
+Console.WriteLine($"LCM => {string.Join(" * ", factors)} = {factors.Aggregate(1L, (acc, x) => acc * x)}");
+
 return 0;