浏览代码

Day 18 part 2 - that was quite tricky with the double counting of lines

Lukas Angerer 2 年之前
父节点
当前提交
ec7ab11a32
共有 7 个文件被更改,包括 140 次插入116 次删除
  1. 38 0
      Day18/CellData.cs
  2. 59 103
      Day18/Field.cs
  3. 20 1
      Day18/Instruction.cs
  4. 3 0
      Day18/Line.cs
  5. 1 1
      Day18/Parser.cs
  6. 9 6
      Day18/Program.cs
  7. 10 5
      Day18/Vec.cs

+ 38 - 0
Day18/CellData.cs

@@ -0,0 +1,38 @@
+namespace Day18;
+
+public class CellData
+{
+    public Vec TopLeft { get; }
+    public Vec BottomRight { get; }
+    public List<Line>? Lines { get; set; }
+    public bool HasCrossing { get; private set; }
+
+    public CellData(Vec tl, Vec br)
+    {
+        TopLeft = tl;
+        BottomRight = br;
+    }
+
+    public long Size()
+    {
+        return (BottomRight.X - TopLeft.X) * (BottomRight.Y - TopLeft.Y);
+    }
+
+    public void Calculate()
+    {
+        foreach (var l in Lines!)
+        {
+            if (l.Dir.IsVertical && l.Start.X == TopLeft.X)
+            {
+                var start = Math.Min(l.Start.Y, l.Start.Y + l.Length * l.Dir.Y);
+                var end = Math.Max(l.Start.Y, l.Start.Y + l.Length * l.Dir.Y);
+
+                if (start <= TopLeft.Y && end >= TopLeft.Y && start <= BottomRight.Y && end >= BottomRight.Y)
+                {
+                    HasCrossing = true;
+                    break;
+                }
+            }
+        }
+    }
+}

+ 59 - 103
Day18/Field.cs

@@ -1,109 +1,87 @@
-using System.Drawing;
-
-using Day17;
-
-namespace Day18;
+namespace Day18;
 
 public class Field
 {
-    private int _minX, _maxX = 0;
-    private int _minY, _maxY = 0;
-    private Vec _pos = new Vec(0, 0);
-    private readonly Dictionary<Vec, CellData> _grid = new Dictionary<Vec, CellData>();
+    private CellData[,]? _grid;
+    private long _perimeter = 0L;
 
-    public Field()
+    public void Apply(List<Instruction> instructions)
     {
-        _grid[_pos] = new CellData(Color.White);
-    }
+        var pos = new Vec(0, 0);
+        var lines = new List<Line>();
+        _perimeter = 0L;
+        foreach (var inst in instructions)
+        {
+            var line = new Line(pos, Vec.Direction(inst.Dir), inst.Num);
+            lines.Add(line);
+            pos = pos.Add(line.Dir.Multiply(line.Length));
+            _perimeter += line.Length;
+        }
 
-    public void Apply(Instruction inst)
-    {
-        var v = Vec.Direction(inst.Dir);
-        for (var i = 0; i < inst.Num; i++)
+        var xNodes = lines.Select(l => l.Start.X).Order().Distinct().ToArray();
+        var yNodes = lines.Select(l => l.Start.Y).Order().Distinct().ToArray();
+
+        _grid = new CellData[xNodes.Length - 1, yNodes.Length - 1];
+        for (var y = 0; y < yNodes.Length - 1; y++)
         {
-            _grid[_pos].Outgoing = v;
-            
-            _pos = _pos.Add(v);
-            _grid.TryAdd(_pos, new CellData(inst.Color));
-            _grid[_pos].Incoming = v;
-            
-            _minX = Math.Min(_minX, _pos.X);
-            _maxX = Math.Max(_maxX, _pos.X);
-            _minY = Math.Min(_minY, _pos.Y);
-            _maxY = Math.Max(_maxY, _pos.Y);
+            for (var x = 0; x < xNodes.Length - 1; x++)
+            {
+                var topLeft = new Vec(xNodes[x], yNodes[y]);
+                var bottomRight = new Vec(xNodes[x + 1], yNodes[y + 1]);
+                var cell = new CellData(topLeft, bottomRight);
+                _grid[x, y] = cell;
+
+                cell.Lines = lines
+                    .Where(l => l.Dir.IsVertical && l.Start.X == topLeft.X)
+                    .ToList();
+                
+                cell.Calculate();
+            }
         }
     }
 
-    public int Fill()
+    public long GetArea()
     {
-        var count = 0;
-        for (var y = _minY; y < _maxY + 1; y++)
+        if (_grid == null)
+        {
+            throw new NullReferenceException("_grid");
+        }
+        
+        var count = 0L;
+        for (var y = 0; y < _grid.GetLength(1); y++)
         {
-            var lastCorner = 0;
-            var transitions = 0;
-            for (var x = _minX; x < _maxX + 1; x++)
+            var crossings = 0;
+            for (var x = 0; x < _grid.GetLength(0); x++)
             {
-                var v = new Vec(x, y);
-                if (_grid.TryGetValue(v, out CellData? d))
+                var cell = _grid[x, y];
+                crossings += cell.HasCrossing ? 1 : 0;
+                if (crossings % 2 == 1)
                 {
-                    var data = d!;
-                    count++;
-                    var cornerNum = data.CornerNum();
-                    if (cornerNum == 0)
-                    {
-                        if (data.Incoming!.Value.IsVertical)
-                        {
-                            transitions++;
-                        }
-                    }
-                    else
-                    {
-                        if (lastCorner == 0)
-                        {
-                            lastCorner = cornerNum;
-                        }
-                        else if (lastCorner == -cornerNum)
-                        {
-                            transitions++;
-                            lastCorner = 0;
-                        }
-                        else
-                        {
-                            lastCorner = 0;
-                        }
-                    }
-                }
-                else
-                {
-                    if (transitions % 2 == 1)
-                    {
-                        count++;
-                    }
+                    count += cell.Size();
                 }
             }
         }
 
-        return count;
-    }
+        count += _perimeter / 2 + 1;
 
-    private int CornerNum(Vec vec)
-    {
-        var above = _grid.ContainsKey(vec.Add(new Vec(0, -1)));
-        var below = _grid.ContainsKey(vec.Add(new Vec(0, 1)));
-        return above == below
-            ? 0
-            : above
-                ? -1
-                : 1;
+        return count;
     }
 
     public void Print()
     {
-        for (var y = _minY; y < _maxY + 1; y++)
+        if (_grid == null)
+        {
+            throw new NullReferenceException("_grid");
+        }
+        
+        for (var y = 0; y < _grid.GetLength(1); y++)
         {
-            for (var x = _minX; x < _maxX + 1; x++)
+            var crossings = 0;
+            for (var x = 0; x < _grid.GetLength(0); x++)
             {
-                if (_grid.ContainsKey(new Vec(x, y)))
+                var cell = _grid[x, y];
+                crossings += cell.HasCrossing ? 1 : 0;
+                if (crossings % 2 == 1)
                 {
                     Console.Write('#');
                 }
@@ -118,26 +96,4 @@ public class Field
 
         Console.WriteLine();
     }
-
-    private class CellData
-    {
-        public Color Color { get; }
-        public Vec? Outgoing { get; set; }
-        public Vec? Incoming { get; set; }
-
-        public CellData(Color color)
-        {
-            Color = color;
-        }
-
-        public int CornerNum()
-        {
-            if (Incoming != null && Outgoing != null)
-            {
-                var n = Incoming.Value.Cross(Outgoing.Value);
-                return Math.Abs(n) == 1 ? n : 0;
-            }
-            return 0;
-        }
-    }
 }

+ 20 - 1
Day18/Instruction.cs

@@ -2,4 +2,23 @@
 
 namespace Day18;
 
-public record Instruction(char Dir, int Num, Color Color);
+public record Instruction(char Dir, int Num, byte[] Scramble)
+{
+    private static readonly IDictionary<int, char> DirMap = new Dictionary<int, char>
+    {
+        [0] = 'R',
+        [1] = 'D',
+        [2] = 'L',
+        [3] = 'U'
+    };
+    
+    public Instruction Unscramble()
+    {
+        
+        var code = BitConverter.ToInt32(Scramble.Reverse().Append((byte)0).ToArray());
+        var dirIndex = code & 15; 
+        var num = code >> 4;
+
+        return new Instruction(DirMap[dirIndex], num, new byte[] { });
+    }
+}

+ 3 - 0
Day18/Line.cs

@@ -0,0 +1,3 @@
+namespace Day18;
+
+public record Line(Vec Start, Vec Dir, int Length);

+ 1 - 1
Day18/Parser.cs

@@ -25,7 +25,7 @@ public partial class Parser
             yield return new Instruction(
                 match.Groups[1].Value[0],
                 int.Parse(match.Groups[2].Value),
-                (Color)colorConverter.ConvertFromString(match.Groups[3].Value)!);
+                Convert.FromHexString(match.Groups[3].Value.Substring(1)));
         }
     }
 }

+ 9 - 6
Day18/Program.cs

@@ -19,13 +19,16 @@ var parser = new Parser();
 var instructions = parser.Parse(inputFile).ToList();
 var field = new Field();
 
-foreach (var i in instructions)
-{
-    Console.WriteLine($"{i.Dir}: {i.Num}");
-    field.Apply(i);
-}
+field.Apply(instructions);
+field.Print();
+var volume = field.GetArea();
+Console.WriteLine();
+Console.WriteLine($"Volume: {volume}");
+
+field = new Field();
+field.Apply(instructions.Select(i => i.Unscramble()).ToList());
 field.Print();
-var volume = field.Fill();
+volume = field.GetArea();
 Console.WriteLine();
 Console.WriteLine($"Volume: {volume}");
 

+ 10 - 5
Day18/Vec.cs

@@ -1,14 +1,14 @@
-namespace Day17;
+namespace Day18;
 
 public record struct Vec
 {
-    public int X { get; }
-    public int Y { get; }
+    public long X { get; }
+    public long Y { get; }
 
     public bool IsHorizontal => Y == 0;
     public bool IsVertical => X == 0;
 
-    public Vec(int x, int y)
+    public Vec(long x, long y)
     {
         X = x;
         Y = y;
@@ -31,7 +31,12 @@ public record struct Vec
         return new Vec(X + other.X, Y + other.Y);
     }
 
-    public int Cross(Vec other)
+    public Vec Multiply(int f)
+    {
+        return new Vec(f * X, f * Y);
+    }
+
+    public long Cross(Vec other)
     {
         return X * other.Y - other.X * Y;
     }