-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay16.cs
99 lines (79 loc) · 3.28 KB
/
Day16.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
using Aoc2024Net.Utilities;
namespace Aoc2024Net.Days
{
internal sealed class Day16 : Day
{
private record Path(ICollection<Coordinate> Coordinates, Coordinate Direction, long Score);
private static readonly Dictionary<Coordinate, Coordinate> RightTurns = new()
{
[new(0, 1)] = new(-1, 0),
[new(0, -1)] = new(1, 0),
[new(1, 0)] = new(0, 1),
[new(-1, 0)] = new(0, -1),
};
private static readonly Dictionary<Coordinate, Coordinate> LeftTurns = new()
{
[new(0, 1)] = new(1, 0),
[new(0, -1)] = new(-1, 0),
[new(1, 0)] = new(0, -1),
[new(-1, 0)] = new(0, 1),
};
public override object? SolvePart1() =>
GetBestPaths().First().Score;
public override object? SolvePart2() =>
GetBestPaths().SelectMany(p => p.Coordinates).Distinct().Count();
private ICollection<Path> GetBestPaths()
{
var (grid, width, height) = InputData.GetInputCharGrid();
var allCoordinates = grid.GetAllCoordinates();
var start = allCoordinates.First(c => grid.At(c) == 'S');
var end = allCoordinates.First(c => grid.At(c) == 'E');
var visitedCounts = new Dictionary<Coordinate, int>();
var maxPassesThroughSameTile = 20;
var queue = new PriorityQueue<Path, long>();
void EnqueuePath(Path path) =>
queue.Enqueue(path, path.Score);
EnqueuePath(new Path([start], new(1, 0), 0));
var bestPaths = new List<Path>();
var bestScore = long.MaxValue;
while (queue.Count > 0)
{
var currentPath = queue.Dequeue();
var currentPathEnd = currentPath.Coordinates.Last();
if ((visitedCounts.TryGetValue(currentPathEnd, out var count) && count > maxPassesThroughSameTile) ||
grid.At(currentPathEnd) == '#' ||
currentPath.Score > bestScore)
continue;
if (currentPathEnd == end)
{
bestPaths.Add(currentPath);
bestScore = currentPath.Score;
continue;
}
if (!visitedCounts.ContainsKey(currentPathEnd))
visitedCounts[currentPathEnd] = 0;
visitedCounts[currentPathEnd]++;
var nextPaths = new[]
{
new Path(
[..currentPath.Coordinates, currentPathEnd + currentPath.Direction],
currentPath.Direction,
currentPath.Score + 1),
new Path(
[.. currentPath.Coordinates],
LeftTurns[currentPath.Direction],
currentPath.Score + 1000),
new Path(
[.. currentPath.Coordinates],
RightTurns[currentPath.Direction],
currentPath.Score + 1000),
};
foreach (var path in nextPaths)
{
EnqueuePath(path);
}
}
return bestPaths;
}
}
}