mirror of
https://github.com/parnic/advent-of-code-2023.git
synced 2025-06-16 16:50:14 -05:00
105 lines
3.4 KiB
C#
105 lines
3.4 KiB
C#
using aoc2023.Util;
|
|
|
|
namespace aoc2023;
|
|
|
|
internal class Day17 : Day
|
|
{
|
|
private int[,] heatmap = new int[1, 1];
|
|
private int width;
|
|
private int height;
|
|
internal override void Parse()
|
|
{
|
|
var lines = Parsing.ReadAllLines($"{GetDay()}").ToList();
|
|
height = lines.Count;
|
|
width = lines[0].Length;
|
|
heatmap = new int[width, height];
|
|
for (int row = 0; row < height; row++)
|
|
{
|
|
for (int col = 0; col < width; col++)
|
|
{
|
|
heatmap[col, row] = int.Parse(lines[row][col].ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
private static readonly ivec2[] directions = [ivec2.LEFT, ivec2.UP, ivec2.RIGHT, ivec2.DOWN];
|
|
List<(ivec2 pos, int dirIdx, int steps)> GetNeighbors(ivec2 position, ivec2 direction, int steps, int minSteps, int maxSteps)
|
|
{
|
|
List<(ivec2 pos, int dirIdx, int steps)> neighbors = [];
|
|
|
|
var idx = directions.IndexOf(direction);
|
|
List<int> newDirectionsIdx = new(directions.Length);
|
|
if (steps < maxSteps)
|
|
{
|
|
newDirectionsIdx.Add(idx);
|
|
}
|
|
|
|
if (steps >= minSteps)
|
|
{
|
|
for (int i = 1; i < directions.Length; i++)
|
|
{
|
|
newDirectionsIdx.Add((idx + i) % directions.Length);
|
|
}
|
|
}
|
|
|
|
foreach (var dirIdx in newDirectionsIdx)
|
|
{
|
|
int stepsToDir = directions[dirIdx] == direction ? steps : 0;
|
|
neighbors.Add((position + directions[dirIdx], dirIdx, stepsToDir + 1));
|
|
}
|
|
|
|
return neighbors;
|
|
}
|
|
|
|
private int Solve(int minSteps, int maxSteps)
|
|
{
|
|
int result = int.MaxValue;
|
|
ivec2 goal = new(width - 1, height - 1);
|
|
|
|
PriorityQueue<(ivec2 pos, ivec2 dir, int steps), int> pq = new();
|
|
pq.Enqueue((new ivec2(0, 0), ivec2.RIGHT, 0), heatmap[0, 0]);
|
|
pq.Enqueue((new ivec2(0, 0), ivec2.DOWN, 0), heatmap[0, 0]);
|
|
Dictionary<int, int> visited = [];
|
|
while (pq.TryDequeue(out (ivec2 pos, ivec2 dir, int steps) element, out int cost))
|
|
{
|
|
foreach (var neighbor in GetNeighbors(element.pos, element.dir, element.steps, minSteps, maxSteps))
|
|
{
|
|
if (!neighbor.pos.IsWithinRange(0, 0, width - 1, height - 1))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
int nextCost = cost + heatmap[neighbor.pos.x, neighbor.pos.y];
|
|
var hash = HashCode.Combine(neighbor.pos, neighbor.dirIdx, neighbor.steps);
|
|
visited.TryAdd(hash, int.MaxValue);
|
|
if (nextCost < visited[hash] && nextCost < result)
|
|
{
|
|
visited[hash] = nextCost;
|
|
if (neighbor.pos == goal && element.steps >= minSteps)
|
|
{
|
|
result = nextCost;
|
|
}
|
|
else
|
|
{
|
|
pq.Enqueue((neighbor.pos, directions[neighbor.dirIdx], neighbor.steps), nextCost);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result + heatmap[goal.x, goal.y];
|
|
}
|
|
|
|
internal override string Part1()
|
|
{
|
|
var result = Solve(0, 3);
|
|
return $"Least heat loss with 3 maximum steps in one direction: <+white>{result}";
|
|
}
|
|
|
|
internal override string Part2()
|
|
{
|
|
var result = Solve(4, 10);
|
|
return $"Least heat loss with 4 minimum and 10 maximum steps in one direction: <+white>{result}";
|
|
}
|
|
}
|