about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBen Harris <bharris@HAGERTY.com>2020-12-02 11:44:03 -0500
committerBen Harris <bharris@HAGERTY.com>2020-12-02 11:44:03 -0500
commit449e14d5e25f92029d8a7f6cfb036958f0157744 (patch)
tree04b390ff869b0914cad76cba78ec94ee9b407013
parent3111405d8c846186d5c4df3bc3189b5933cca956 (diff)
day 15
-rw-r--r--Day15.cs203
1 files changed, 201 insertions, 2 deletions
diff --git a/Day15.cs b/Day15.cs
index fa2d510..5195511 100644
--- a/Day15.cs
+++ b/Day15.cs
@@ -1,3 +1,5 @@
+using System;
+using System.Collections.Generic;
 using System.Linq;
 using aoc2019.lib;
 
@@ -6,6 +8,7 @@ namespace aoc2019
     internal sealed class Day15 : Day
     {
         private readonly IntCodeVM vm;
+        private bool verbose = false;
 
         public Day15()
         {
@@ -16,12 +19,208 @@ namespace aoc2019
 
         protected override string Part1()
         {
-            return "intcode solution";
+            vm.Reset();
+            var currentLocation = new Location(0, 0);
+            var halt = IntCodeVM.HaltType.Waiting;
+            while (halt == IntCodeVM.HaltType.Waiting)
+            {
+                var direction = currentLocation.NextDirection();
+                if (direction <= 4)
+                {
+                    var (x, y) = currentLocation.Neighbor(direction);
+                    if (Location.GetLocation(x, y) == null)
+                    {
+                        halt = vm.Run(direction);
+                        switch (vm.Result)
+                        {
+                            case Location.Wall:
+                                new Location(x, y, Location.Opposites[direction], Location.Wall);
+                                break;
+                            case Location.Empty:
+                                currentLocation = new Location(x, y, Location.Opposites[direction]);
+                                break;
+                            case Location.System:
+                                currentLocation = new Location(x, y, Location.Opposites[direction], Location.System);
+                                break;
+                            default:
+                                throw new Exception($"Unknown IntCodeVM response: {vm.Result}");
+                        }
+                    }
+                }
+                else
+                {
+                    direction = currentLocation.PreviousDirection;
+                    if (direction > 0)
+                    {
+                        halt = vm.Run(direction);
+                        switch (vm.Result)
+                        {
+                            case Location.Empty:
+                            case Location.System:
+                                currentLocation = Location.GetLocation(currentLocation.Neighbor(direction));
+                                break;
+                            default:
+                                throw new Exception($"Unknown or unexpected response for previous room: {vm.Result}");
+                        }
+                    }
+                    else
+                    {
+                        if (verbose)
+                        {
+                            // find extents of canvas
+                            int xMin, xMax, yMin, yMax;
+                            xMin = yMin = int.MaxValue;
+                            xMax = yMax = int.MinValue;
+                            foreach (var (x, y) in Location.AllLocations.Keys)
+                            {
+                                if (x < xMin) xMin = x;
+                                if (x > xMax) xMax = x;
+                                if (y < yMin) yMin = y;
+                                if (y > yMax) yMax = y;
+                            }
+
+                            Console.WriteLine($"Canvas extends from ({xMin}, {yMin}) to ({xMax}, {yMax})");
+
+                            // print board
+                            for (var y = yMin; y <= yMax; y++)
+                            {
+                                var line = "";
+                                for (var x = xMin; x <= xMax; x++)
+                                    if (Location.AllLocations.ContainsKey((x, y)))
+                                        line += Location.AllLocations[(x, y)].Image();
+                                    else
+                                        line += "@";
+
+                                Console.WriteLine(line);
+                            }
+                        }
+
+                        currentLocation = Location.OxygenLocation;
+                        var distance = 0;
+                        while (currentLocation.PreviousDirection != 0)
+                        {
+                            distance++;
+                            currentLocation = Location.GetLocation(currentLocation.PreviousLocation());
+                        }
+
+                        return $"{distance}";
+                    }
+                }
+            }
+
+            return "";
         }
 
         protected override string Part2()
         {
-            return "";
+            var changed = true;
+            while (changed)
+            {
+                changed = false;
+                foreach (var location in Location.AllLocations.Values)
+                    changed = location.UpdateDistanceToOxygenSystem() || changed;
+            }
+
+            return Location.AllLocations.Values
+                .Where(l => !l.IsWall)
+                .Max(l => l.DistanceToOxygenSystem)
+                .ToString();
+        }
+
+        private class Location
+        {
+            public const int Wall = 0;
+            public const int Empty = 1;
+            public const int System = 2;
+
+            private static readonly int[] Dx = {0, 0, 0, 1, -1};
+            private static readonly int[] Dy = {0, 1, -1, 0, 0};
+            public static readonly int[] Opposites = {0, 2, 1, 4, 3};
+
+            public static readonly Dictionary<(int x, int y), Location>
+                AllLocations = new Dictionary<(int x, int y), Location>();
+
+            private readonly int currentType;
+            public int DistanceToOxygenSystem = int.MaxValue - 1;
+
+            private int searchDirection = 1;
+
+            public Location(int x, int y, int prev = 0, int type = Empty)
+            {
+                PreviousDirection = prev;
+                currentType = type;
+                X = x;
+                Y = y;
+
+                if (type == System)
+                {
+                    OxygenLocation = this;
+                    DistanceToOxygenSystem = 0;
+                    // Console.WriteLine($"Found Oxygen System at ({x}, {y})");
+                }
+
+                AllLocations.Add((x, y), this);
+            }
+
+            public static Location OxygenLocation { get; private set; }
+            public int PreviousDirection { get; }
+            private int X { get; }
+            private int Y { get; }
+
+            public bool IsWall => currentType == Wall;
+
+            public string Image()
+            {
+                return currentType switch
+                {
+                    Wall => "\u2587",
+                    Empty => X == 0 && Y == 0 ? "S" : " ",
+                    System => "O",
+                    _ => "?"
+                };
+            }
+
+            public bool UpdateDistanceToOxygenSystem()
+            {
+                if (currentType != Empty) return false;
+
+                foreach (var direction in Enumerable.Range(1, 4))
+                {
+                    var distance = GetLocation(Neighbor(direction))?.DistanceToOxygenSystem ?? int.MaxValue;
+                    if (distance + 1 < DistanceToOxygenSystem)
+                    {
+                        DistanceToOxygenSystem = distance + 1;
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+
+            public (int, int) Neighbor(int direction)
+            {
+                return (X + Dx[direction], Y + Dy[direction]);
+            }
+
+            public (int, int) PreviousLocation()
+            {
+                return Neighbor(PreviousDirection);
+            }
+
+            public int NextDirection()
+            {
+                return searchDirection++;
+            }
+
+            public static Location GetLocation(int x, int y)
+            {
+                return AllLocations.ContainsKey((x, y)) ? AllLocations[(x, y)] : null;
+            }
+
+            public static Location GetLocation((int x, int y) coords)
+            {
+                return GetLocation(coords.x, coords.y);
+            }
         }
     }
 }
\ No newline at end of file