Lukas Angerer преди 2 години
родител
ревизия
bf9eb9809a
променени са 6 файла, в които са добавени 182 реда и са изтрити 2 реда
  1. 35 2
      Day19/Data.cs
  2. 47 0
      Day19/PartRange.cs
  3. 5 0
      Day19/Program.cs
  4. 43 0
      Day19/Range.cs
  5. 49 0
      Day19/Rule.cs
  6. 3 0
      Day19/RuleResultRange.cs

+ 35 - 2
Day19/Data.cs

@@ -19,12 +19,45 @@ public record Data(IDictionary<string, Rule> Rules, IList<Part> Parts)
             {
                 sum += part.Total;
                 Console.WriteLine("ACCEPTED");
-                Console.WriteLine();
             }
             else
             {
                 Console.WriteLine("REJECTED");
-                Console.WriteLine();
+            }
+        }
+
+        return sum;
+    }
+
+    public long ComputePermutations()
+    {
+        var sum = 0L;
+        var queue = new Queue<RuleResultRange>();
+        queue.Enqueue(new RuleResultRange(new PartRange(), "in"));
+        
+        while (queue.Count > 0)
+        {
+            var current = queue.Dequeue();
+            Console.WriteLine($"Applying {current.Next} to {current.Part}");
+
+            var next = current.Next!;
+            if (next == "A")
+            {
+                sum += current.Part.Total();
+                Console.WriteLine("ACCEPTED");
+            }
+            else if (next == "R")
+            {
+                Console.WriteLine("REJECTED");
+            }
+            else
+            {
+                var rule = Rules[next];
+
+                foreach (var r in rule.Apply(current.Part))
+                {
+                    queue.Enqueue(r);
+                }
             }
         }
 

+ 47 - 0
Day19/PartRange.cs

@@ -0,0 +1,47 @@
+namespace Day19;
+
+public class PartRange
+{
+    private readonly IDictionary<string, Range> _dict;
+    
+    public PartRange()
+    {
+        _dict = new Dictionary<string, Range>
+        {
+            ["x"] = new Range(1, 4000),
+            ["m"] = new Range(1, 4000),
+            ["a"] = new Range(1, 4000),
+            ["s"] = new Range(1, 4000),
+        };
+    }
+    
+    private PartRange(PartRange original)
+    {
+        _dict = new Dictionary<string, Range>(original._dict);
+    }
+
+    public Range Get(string property)
+    {
+        return _dict[property];
+    }
+
+    public PartRange Update(string property, Range range)
+    {
+        var copy = new PartRange(this);
+        copy._dict[property] = range;
+        return copy;
+    }
+
+    public long Total()
+    {
+        return Get("x").Size
+               * Get("m").Size
+               * Get("a").Size
+               * Get("s").Size;
+    }
+
+    public override string ToString()
+    {
+        return $"x = {Get("x")}, m = {Get("m")}, a = {Get("a")}, s = {Get("s")}, ";
+    }
+}

+ 5 - 0
Day19/Program.cs

@@ -21,4 +21,9 @@ var result = data.Process();
 Console.WriteLine();
 Console.WriteLine($"Result: {result}");
 
+Console.WriteLine();
+var permutations = data.ComputePermutations();
+Console.WriteLine();
+Console.WriteLine($"Permutations: {permutations}");
+
 return 0;

+ 43 - 0
Day19/Range.cs

@@ -0,0 +1,43 @@
+namespace Day19;
+
+public record Range(int Start, int End)
+{
+    public static Range Empty = new Range(-1, -1);
+
+    public long Size => this == Empty ? 0 : (End - Start + 1);
+    
+    public Range LessThan(int value)
+    {
+        if (value <= Start)
+        {
+            return Empty;
+        }
+
+        if (value > End)
+        {
+            return this;
+        }
+
+        return this with { End = value - 1 };
+    }
+
+    public Range GreaterThan(int value)
+    {
+        if (value >= End)
+        {
+            return Empty;
+        }
+
+        if (value < Start)
+        {
+            return this;
+        }
+
+        return this with { Start = value + 1 };
+    }
+    
+    public override string ToString()
+    {
+        return $"{Start} - {End}";
+    }
+}

+ 49 - 0
Day19/Rule.cs

@@ -38,9 +38,24 @@ public partial class Rule
         throw new Exception("Rule should always match");
     }
     
+    public IEnumerable<RuleResultRange> Apply(PartRange p)
+    {
+        var range = p;
+        foreach (var item in _items)
+        {
+            var result = item.Apply(range).ToList();
+            yield return result.First();
+            if (result.Count > 1)
+            {
+                range = result.Last().Part;
+            }
+        }
+    }
+
     private interface IRuleItem
     {
         string? Apply(Part p);
+        IEnumerable<RuleResultRange> Apply(PartRange p);
     }
 
     private class Item : IRuleItem
@@ -72,6 +87,35 @@ public partial class Rule
 
             return null;
         }
+        
+        public IEnumerable<RuleResultRange> Apply(PartRange p)
+        {
+            var range = p.Get(_property);
+            
+            if (_op == "<")
+            {
+                yield return new RuleResultRange(
+                    p.Update(_property, range.LessThan(_value)),
+                    _next
+                );
+                yield return new RuleResultRange(
+                    p.Update(_property, range.GreaterThan(_value - 1)),
+                    null
+                );
+            }
+
+            if (_op == ">")
+            {
+                yield return new RuleResultRange(
+                    p.Update(_property, range.GreaterThan(_value)),
+                    _next
+                );
+                yield return new RuleResultRange(
+                    p.Update(_property, range.LessThan(_value + 1)),
+                    null
+                );
+            }
+        }
 
         public override string ToString()
         {
@@ -93,6 +137,11 @@ public partial class Rule
             return _next;
         }
 
+        public IEnumerable<RuleResultRange> Apply(PartRange p)
+        {
+            yield return new RuleResultRange(p, _next);
+        }
+
         public override string ToString()
         {
             return $"Terminal<{_next}>";

+ 3 - 0
Day19/RuleResultRange.cs

@@ -0,0 +1,3 @@
+namespace Day19;
+
+public record RuleResultRange(PartRange Part, string? Next);