-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay20.cs
143 lines (114 loc) · 4.32 KB
/
Day20.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using Aoc2024Net.Utilities;
using System.Diagnostics;
namespace Aoc2024Net.Days
{
internal sealed class Day20 : Day
{
private record PathCoordinate(Coordinate Coordinate, int PathLength);
private static readonly Coordinate[] Moves =
[
new(0, 1),
new(0, -1),
new(1, 0),
new(-1, 0),
];
public override object? SolvePart1()
{
var (grid, width, height) = InputData.GetInputCharGrid();
var ccc = grid.GetAllCoordinates();
var start = ccc.First(c => grid.At(c) == 'S');
var end = ccc.First(c => grid.At(c) == 'E');
var bestPath = GetPath(grid, width, height, start, end);
var bestPathLength = bestPath.Count - 1;
var possibleCheatPositions = bestPath
.SelectMany(p => Moves.Select(m => p + m))
.Where(p => grid.At(p) == '#')
.Distinct()
.ToArray();
var dict = new Dictionary<int, int>();
var i = 0;
foreach (var c in possibleCheatPositions)
{
i++;
Debug.WriteLine($"{i} / {possibleCheatPositions.Length}");
grid.SetAt(c, '.');
var p = GetPathLength(grid, width, height, start, end, bestPathLength);
if (p != null)
{
var diff = bestPathLength - p.Value;
if (diff > 0)
{
if (!dict.ContainsKey(diff))
dict[diff] = 0;
dict[diff]++;
}
}
grid.SetAt(c, '#');
}
return dict.Where(kv => kv.Key >= 100).Sum(kv => kv.Value);
}
public override object? SolvePart2() => null;
private static List<Coordinate> GetPath(
char[,] grid,
int width,
int height,
Coordinate start,
Coordinate end)
{
var visited = new HashSet<Coordinate>();
var queue = new PriorityQueue<List<Coordinate>, int>();
void EnqueuePath(List<Coordinate> path) =>
queue.Enqueue(path, path.Count);
EnqueuePath(new List<Coordinate> { start });
while (queue.Count > 0)
{
var currentPathCoordinate = queue.Dequeue();
var currentPathEnd = currentPathCoordinate.Last();
if (!visited.Add(currentPathEnd) ||
!grid.IsInGrid(width, height, currentPathEnd) ||
grid.At(currentPathEnd) == '#')
continue;
if (currentPathEnd == end)
return currentPathCoordinate;
foreach (var move in Moves)
{
EnqueuePath([.. currentPathCoordinate, currentPathEnd + move]);
}
}
return null;
}
private static int? GetPathLength(
char[,] grid,
int width,
int height,
Coordinate start,
Coordinate end,
int threshold)
{
var visited = new HashSet<Coordinate>();
var queue = new PriorityQueue<PathCoordinate, int>();
void EnqueuePath(PathCoordinate path) =>
queue.Enqueue(path, path.PathLength);
EnqueuePath(new PathCoordinate(start, 0));
while (queue.Count > 0)
{
var currentPathCoordinate = queue.Dequeue();
var currentPathEnd = currentPathCoordinate.Coordinate;
if (!visited.Add(currentPathEnd) ||
!grid.IsInGrid(width, height, currentPathEnd) ||
grid.At(currentPathEnd) == '#' ||
currentPathCoordinate.PathLength >= threshold)
continue;
if (currentPathEnd == end)
return currentPathCoordinate.PathLength;
foreach (var move in Moves)
{
EnqueuePath(new PathCoordinate(
currentPathEnd + move,
currentPathCoordinate.PathLength + 1));
}
}
return null;
}
}
}