2021-11-09 21:52:21 +00:00
|
|
|
namespace aoc2019;
|
2019-12-16 06:51:19 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
public sealed class Day15 : Day
|
2019-12-16 06:51:19 +00:00
|
|
|
{
|
2021-11-09 21:52:21 +00:00
|
|
|
private readonly bool verbose = false;
|
|
|
|
private readonly IntCodeVM vm;
|
2019-12-16 06:51:19 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
public Day15() : base(15, "Oxygen System")
|
|
|
|
{
|
2021-12-01 19:56:16 +00:00
|
|
|
vm = new(Input.First());
|
2021-11-09 21:52:21 +00:00
|
|
|
}
|
2019-12-16 06:51:19 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
public override string Part1()
|
|
|
|
{
|
|
|
|
vm.Reset();
|
|
|
|
var currentLocation = new Location(0, 0);
|
|
|
|
var halt = IntCodeVM.HaltType.Waiting;
|
|
|
|
while (halt == IntCodeVM.HaltType.Waiting)
|
2019-12-16 06:51:19 +00:00
|
|
|
{
|
2021-11-09 22:02:38 +00:00
|
|
|
var direction = currentLocation!.NextDirection();
|
2021-11-09 21:52:21 +00:00
|
|
|
if (direction <= 4)
|
2020-12-02 16:44:03 +00:00
|
|
|
{
|
2021-11-09 21:52:21 +00:00
|
|
|
var (x, y) = currentLocation.Neighbor(direction);
|
|
|
|
if (Location.GetLocation(x, y) == null)
|
2020-12-02 16:44:03 +00:00
|
|
|
{
|
2021-11-09 21:52:21 +00:00
|
|
|
halt = vm.Run(direction);
|
2021-11-09 21:59:05 +00:00
|
|
|
switch (vm.Result)
|
2020-12-02 16:44:03 +00:00
|
|
|
{
|
2021-11-09 21:59:05 +00:00
|
|
|
case Location.Wall:
|
|
|
|
_ = new Location(x, y, Location.Opposites[direction], Location.Wall);
|
|
|
|
break;
|
|
|
|
case Location.Empty:
|
2021-12-01 19:56:16 +00:00
|
|
|
currentLocation = new(x, y, Location.Opposites[direction]);
|
2021-11-09 21:59:05 +00:00
|
|
|
break;
|
|
|
|
case Location.System:
|
2021-12-01 19:56:16 +00:00
|
|
|
currentLocation = new(x, y, Location.Opposites[direction], Location.System);
|
2021-11-09 21:59:05 +00:00
|
|
|
break;
|
|
|
|
default:
|
2021-12-01 19:56:16 +00:00
|
|
|
throw new($"Unknown IntCodeVM response: {vm.Result}");
|
2021-11-09 21:59:05 +00:00
|
|
|
}
|
2020-12-02 16:44:03 +00:00
|
|
|
}
|
2021-11-09 21:52:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
direction = currentLocation.PreviousDirection;
|
|
|
|
if (direction > 0)
|
2020-12-02 16:44:03 +00:00
|
|
|
{
|
2021-11-09 21:52:21 +00:00
|
|
|
halt = vm.Run(direction);
|
2021-11-09 22:02:38 +00:00
|
|
|
currentLocation = vm.Result switch
|
2020-12-02 16:44:03 +00:00
|
|
|
{
|
2021-11-09 22:02:38 +00:00
|
|
|
Location.Empty or Location.System => Location.GetLocation(currentLocation.Neighbor(direction)),
|
2021-12-01 19:56:16 +00:00
|
|
|
_ => throw new($"Unknown or unexpected response for previous room: {vm.Result}")
|
2021-11-09 22:02:38 +00:00
|
|
|
};
|
2021-11-09 21:52:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (verbose)
|
2020-12-02 16:44:03 +00:00
|
|
|
{
|
2021-11-09 21:52:21 +00:00
|
|
|
// 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)
|
2020-12-02 16:44:03 +00:00
|
|
|
{
|
2021-11-09 21:52:21 +00:00
|
|
|
if (x < xMin) xMin = x;
|
|
|
|
if (x > xMax) xMax = x;
|
|
|
|
if (y < yMin) yMin = y;
|
|
|
|
if (y > yMax) yMax = y;
|
2020-12-02 16:44:03 +00:00
|
|
|
}
|
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
Console.WriteLine($"Canvas extends from ({xMin}, {yMin}) to ({xMax}, {yMax})");
|
|
|
|
|
|
|
|
// print board
|
|
|
|
for (var y = yMin; y <= yMax; y++)
|
2020-12-02 16:44:03 +00:00
|
|
|
{
|
2021-11-09 21:52:21 +00:00
|
|
|
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);
|
2020-12-02 16:44:03 +00:00
|
|
|
}
|
2021-11-09 21:52:21 +00:00
|
|
|
}
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
currentLocation = Location.OxygenLocation;
|
|
|
|
var distance = 0;
|
2021-11-09 22:02:38 +00:00
|
|
|
while (currentLocation?.PreviousDirection != 0)
|
2021-11-09 21:52:21 +00:00
|
|
|
{
|
|
|
|
distance++;
|
2021-11-09 22:02:38 +00:00
|
|
|
currentLocation = Location.GetLocation(currentLocation!.PreviousLocation());
|
2020-12-02 16:44:03 +00:00
|
|
|
}
|
2021-11-09 21:52:21 +00:00
|
|
|
|
|
|
|
return $"{distance}";
|
2020-12-02 16:44:03 +00:00
|
|
|
}
|
|
|
|
}
|
2019-12-16 06:51:19 +00:00
|
|
|
}
|
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
return "";
|
|
|
|
}
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
public override string Part2()
|
|
|
|
{
|
|
|
|
var changed = true;
|
|
|
|
while (changed)
|
|
|
|
{
|
|
|
|
changed = false;
|
|
|
|
foreach (var location in Location.AllLocations.Values)
|
|
|
|
changed = location.UpdateDistanceToOxygenSystem() || changed;
|
2020-12-02 16:44:03 +00:00
|
|
|
}
|
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
return Location.AllLocations.Values
|
|
|
|
.Where(l => !l.IsWall)
|
|
|
|
.Max(l => l.DistanceToOxygenSystem)
|
|
|
|
.ToString();
|
|
|
|
}
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
private class Location
|
|
|
|
{
|
|
|
|
public const int Wall = 0;
|
|
|
|
public const int Empty = 1;
|
|
|
|
public const int System = 2;
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
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 };
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
public static readonly Dictionary<(int x, int y), Location> AllLocations = new();
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
private readonly int currentType;
|
|
|
|
public int DistanceToOxygenSystem = int.MaxValue - 1;
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
private int searchDirection = 1;
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
public Location(int x, int y, int prev = 0, int type = Empty)
|
|
|
|
{
|
|
|
|
PreviousDirection = prev;
|
|
|
|
currentType = type;
|
|
|
|
X = x;
|
|
|
|
Y = y;
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
if (type == System)
|
|
|
|
{
|
|
|
|
OxygenLocation = this;
|
|
|
|
DistanceToOxygenSystem = 0;
|
|
|
|
// Console.WriteLine($"Found Oxygen System at ({x}, {y})");
|
2020-12-02 16:44:03 +00:00
|
|
|
}
|
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
AllLocations.Add((x, y), this);
|
|
|
|
}
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 22:02:38 +00:00
|
|
|
public static Location? OxygenLocation { get; private set; }
|
2021-11-09 21:52:21 +00:00
|
|
|
public int PreviousDirection { get; }
|
|
|
|
private int X { get; }
|
|
|
|
private int Y { get; }
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
public bool IsWall => currentType == Wall;
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
public string Image()
|
|
|
|
{
|
|
|
|
return currentType switch
|
2020-12-02 16:44:03 +00:00
|
|
|
{
|
2021-11-09 21:52:21 +00:00
|
|
|
Wall => "\u2587",
|
|
|
|
Empty => X == 0 && Y == 0 ? "S" : " ",
|
|
|
|
System => "O",
|
|
|
|
_ => "?"
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool UpdateDistanceToOxygenSystem()
|
|
|
|
{
|
|
|
|
if (currentType != Empty) return false;
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
foreach (var direction in Enumerable.Range(1, 4))
|
|
|
|
{
|
|
|
|
var distance = GetLocation(Neighbor(direction))?.DistanceToOxygenSystem ?? int.MaxValue;
|
|
|
|
if (distance + 1 < DistanceToOxygenSystem)
|
2020-12-02 16:44:03 +00:00
|
|
|
{
|
2021-11-09 21:52:21 +00:00
|
|
|
DistanceToOxygenSystem = distance + 1;
|
|
|
|
return true;
|
2020-12-02 16:44:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
return false;
|
|
|
|
}
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
public (int, int) Neighbor(int direction)
|
|
|
|
{
|
|
|
|
return (X + Dx[direction], Y + Dy[direction]);
|
|
|
|
}
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
public (int, int) PreviousLocation()
|
|
|
|
{
|
|
|
|
return Neighbor(PreviousDirection);
|
|
|
|
}
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 21:52:21 +00:00
|
|
|
public int NextDirection()
|
|
|
|
{
|
|
|
|
return searchDirection++;
|
|
|
|
}
|
2020-12-02 16:44:03 +00:00
|
|
|
|
2021-11-09 22:02:38 +00:00
|
|
|
public static Location? GetLocation(int x, int y)
|
2021-11-09 21:52:21 +00:00
|
|
|
{
|
|
|
|
return AllLocations.ContainsKey((x, y)) ? AllLocations[(x, y)] : null;
|
|
|
|
}
|
|
|
|
|
2021-11-09 22:02:38 +00:00
|
|
|
public static Location? GetLocation((int x, int y) coords)
|
2021-11-09 21:52:21 +00:00
|
|
|
{
|
|
|
|
return GetLocation(coords.x, coords.y);
|
2019-12-16 06:51:19 +00:00
|
|
|
}
|
|
|
|
}
|
2021-11-09 21:52:21 +00:00
|
|
|
}
|