-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDay20.cs
More file actions
140 lines (121 loc) · 4.41 KB
/
Day20.cs
File metadata and controls
140 lines (121 loc) · 4.41 KB
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
using System.Collections.Immutable;
using System.Data;
using System.Runtime.InteropServices.ComTypes;
using _2024.Utils;
namespace _2024._20;
public class Day20 : Base
{
private Dictionary<int, int> Cheats { get; } = new();
private ValueTuple<int, int> Start { get; set; }
private ValueTuple<int, int> End { get; set; }
private List<char[]> Map { get; set; }
private ValueTuple<int, int>[] Directions { get; } = [(0, 1), (0, -1), (1, 0), (-1, 0)];
public Day20(bool example) : base(example)
{
Day = "20";
ParseInput();
}
private void ParseInput()
{
string[] input = ReadInput();
Map = new List<char[]>(input.Length);
foreach ((string line, int idx) in input.Enumerate())
{
Map.Add(line.ToCharArray());
if (line.Contains('S'))
{
Start = (idx, line.IndexOf('S'));
}
if (line.Contains('E'))
{
End = (idx, line.IndexOf('E'));
}
}
Map[Start.Item1][Start.Item2] = '.';
Map[End.Item1][End.Item2] = '.';
}
private int FindPath(out SortedDictionary<ValueTuple<int, int>, int> visited)
{
PriorityQueue<ValueTuple<int, int>, int> path = new();
visited = [];
path.Enqueue(Start, 0);
while (path.TryDequeue(out ValueTuple<int, int> pos, out int stepsTaken))
{
if (pos == End)
{
visited.Add(pos, stepsTaken);
return stepsTaken;
}
if (!visited.TryAdd(pos, stepsTaken))
{
continue;
}
foreach (ValueTuple<int, int> dir in Directions)
{
ValueTuple<int, int> newPos = (pos.Item1+dir.Item1, pos.Item2+dir.Item2);
if(!Map.TryGetValue(newPos, out char value) || value == '#')
{
continue;
}
path.Enqueue(newPos, stepsTaken+1);
}
}
return 0;
}
private int FindDistinctCheats(int stage)
{
int pathWithoutCheats = FindPath(out SortedDictionary<ValueTuple<int, int>, int> path);
int totalNumberOfCheats = 0;
// one could also check all positions where the difference between pos and cheatPos would be
// >= 100 and the distance between the two positions would be <= 20 (for stage 2)
int cap = (stage == 1 ? 2 : 20);
foreach ((ValueTuple<int, int> pos, int time) in path)
{
for (int row = -cap ; row < cap+1; row++)
{
int rowSteps = Math.Abs(row);
for (int col = -(cap-rowSteps); col < (cap-rowSteps)+1; col++)
{
int cheatCost = Math.Abs(col) + rowSteps;
// check if distance is bigger than allowed distance
ValueTuple<int, int> newPos = (pos.Item1+row, pos.Item2+col);
if (!path.TryGetValue(newPos, out int value))
{
continue;
}
int saving = pathWithoutCheats - (time + pathWithoutCheats - value + cheatCost);
//saving = value - time + cheatCost;
if (saving >= (Example ? 1 : 100))
{
totalNumberOfCheats++;
}
}
}
}
return totalNumberOfCheats;
}
private int FindDistinctCheats2(int stage)
{
int pathWithoutCheats = FindPath(out SortedDictionary<ValueTuple<int, int>, int> path);
int totalNumberOfCheats = 0;
foreach ((ValueTuple<int, int> pos, int time) in path)
{
//List<ValueTuple<int, int>> cheats = path.Keys.Where(x => path[x])
}
return totalNumberOfCheats;
}
public override object PartOne()
{
return FindDistinctCheats(1);
}
public override object PartTwo()
{
return FindDistinctCheats2(2);
}
public override void Reset()
{
// removing this line makes part 2 use the cache build from part 1
// effectively making it run instantly
Cheats.Clear();
}
}