Selaa lähdekoodia

Day 5 part 2 - restructuring to allow splitting and mapping ranges

Lukas Angerer 2 vuotta sitten
vanhempi
sitoutus
eef79ed096
5 muutettua tiedostoa jossa 122 lisäystä ja 19 poistoa
  1. 41 3
      Day5/Almanac.cs
  2. 2 2
      Day5/MapParser.cs
  3. 12 0
      Day5/Program.cs
  4. 1 14
      Day5/Range.cs
  5. 66 0
      Day5/RangeMapping.cs

+ 41 - 3
Day5/Almanac.cs

@@ -9,8 +9,8 @@ public class Almanac
     public IList<(string Source, string Destination)> Mappings { get; } =
         new List<(string Source, string Destination)>();
 
-    public Dictionary<string, IList<Range>> MappingData { get; } =
-        new Dictionary<string, IList<Range>>();
+    public Dictionary<string, IList<RangeMapping>> MappingData { get; } =
+        new Dictionary<string, IList<RangeMapping>>();
 
     public IList<long> Map(IList<long> start, string source, string destination)
     {
@@ -24,11 +24,49 @@ public class Almanac
 
         return result;
     }
+    
+    public IList<Range> Map(IList<Range> ranges, string source, string destination)
+    {
+        var result = ranges;
+        var current = source;
+        while (current != destination)
+        {
+            var inQueue = new Queue<Range>(result);
+            result = new List<Range>();
+
+            while (inQueue.Count > 0)
+            {
+                var range = inQueue.Dequeue();
+                foreach (var rangeMapping in MappingData[current].Append(RangeMapping.Identity))
+                {
+                    if (rangeMapping.IsWithin(range))
+                    {
+                        result.Add(rangeMapping.Transform(range));
+                        break;
+                    }
+                    if (rangeMapping.IsOverlap(range))
+                    {
+                        foreach (var fragment in rangeMapping.Split(range))
+                        {
+                            inQueue.Enqueue(fragment);
+                        }
+                        break;
+                    }
+                }
+            }
+            
+            Console.WriteLine($"{current} => {result.Count}");
+            
+            current = Mappings.First(m => m.Source == current).Destination;
+        }
+
+        return result;
+    }
 
     private IList<long> MapSingle(IList<long> start, string source)
     {
         return start
-            .Select(num => MappingData[source].FirstOrDefault(x => x.IsMatch(num), Range.Identity).Transform(num))
+            .Select(num => MappingData[source].FirstOrDefault(x => x.IsMatch(num), RangeMapping.Identity).Transform(num))
             .ToList();
     }
 }

+ 2 - 2
Day5/MapParser.cs

@@ -55,10 +55,10 @@ public partial class MapParser
 
                 if (!almanac.MappingData.ContainsKey(source))
                 {
-                    almanac.MappingData[source] = new Collection<Range>();
+                    almanac.MappingData[source] = new Collection<RangeMapping>();
                 }
                 
-                almanac.MappingData[source].Add(new Range(numbers[1], numbers[0], numbers[2]));
+                almanac.MappingData[source].Add(new RangeMapping(numbers[1], numbers[0], numbers[2]));
             }
         }
         

+ 12 - 0
Day5/Program.cs

@@ -1,5 +1,7 @@
 using Day5;
 
+using Range = Day5.Range;
+
 if (args.Length < 1)
 {
     Console.WriteLine("Requires 1 args: inputFileName");
@@ -14,4 +16,14 @@ var mapped = almanac.Map(almanac.Seeds, "seed", "location");
 Console.WriteLine($"Locations: {string.Join(", ", mapped)}");
 Console.WriteLine($"Min: {mapped.Min()}");
 
+var ranges = almanac.Seeds
+    .Where((_, index) => index % 2 == 0)
+    .Select((start, index) => new Range(start, almanac.Seeds[2 * index + 1]))
+    .ToList();
+
+var locationRanges = almanac.Map(ranges, "seed", "location");
+
+Console.WriteLine();
+Console.WriteLine($"Min: {locationRanges.Min(x => x.Start)}");
+
 return 0;

+ 1 - 14
Day5/Range.cs

@@ -1,16 +1,3 @@
 namespace Day5;
 
-public record Range(long SrcIndex, long DstIndex, long Length)
-{
-    public static Range Identity { get; } = new Range(0, 0, long.MaxValue);
-    
-    public bool IsMatch(long value)
-    {
-        return SrcIndex <= value && value < SrcIndex + Length;
-    }
-
-    public long Transform(long value)
-    {
-        return DstIndex + (value - SrcIndex);
-    }
-}
+public record Range(long Start, long Length);

+ 66 - 0
Day5/RangeMapping.cs

@@ -0,0 +1,66 @@
+namespace Day5;
+
+public record RangeMapping(long SrcIndex, long DstIndex, long Length)
+{
+    public static RangeMapping Identity { get; } = new RangeMapping(0, 0, long.MaxValue);
+    
+    public bool IsMatch(long value)
+    {
+        return SrcIndex <= value && value < SrcIndex + Length;
+    }
+    
+    public bool IsOverlap(Range range)
+    {
+        return range.Start < SrcIndex + Length && range.Start + range.Length > SrcIndex;
+    }
+    
+    public bool IsWithin(Range range)
+    {
+        return range.Start >= SrcIndex && range.Start + range.Length <= SrcIndex + Length;
+    }
+
+    public IEnumerable<Range> Split(Range range)
+    {
+        if (range.Start >= SrcIndex + Length || range.Start + range.Length < SrcIndex)
+        {
+            throw new ArgumentException("Not overlapping");
+        }
+
+        if (range.Start >= SrcIndex && range.Start + range.Length < SrcIndex + Length)
+        {
+            throw new ArgumentException("Already within");
+        }
+
+        if (range.Start < SrcIndex)
+        {
+            yield return new Range(range.Start, SrcIndex - range.Start);
+        }
+
+        if (range.Start + range.Length > SrcIndex + Length)
+        {
+            yield return new Range(SrcIndex + Length, (range.Start + range.Length) - (SrcIndex + Length));
+        }
+        
+        var left = Math.Max(SrcIndex, range.Start);
+        var right = Math.Min(SrcIndex + Length, range.Start + range.Length);
+
+        yield return new Range(SrcIndex + (left - SrcIndex), right - left);
+    }
+
+    public long Transform(long value)
+    {
+        return DstIndex + (value - SrcIndex);
+    }
+
+    public Range Transform(Range range)
+    {
+        if (!IsWithin(range))
+        {
+            throw new ArgumentException("Not in range");
+        }
+        var left = Math.Max(SrcIndex, range.Start);
+        var right = Math.Min(SrcIndex + Length, range.Start + range.Length);
+
+        return new Range(DstIndex + (left - SrcIndex), right - left);
+    }
+}