-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay12.cs
95 lines (80 loc) · 2.96 KB
/
Day12.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
namespace AdventOfCode2022;
internal class Day12
{
private const char StartMarker = 'S';
private const char EndMarker = 'E';
private const char MinHeight = 'a';
private const char MaxHeight = 'z';
private readonly Dictionary<Point, char> _map;
private readonly Dictionary<Point, int> _distances;
private readonly Point _start;
private readonly Point _end;
public Day12(IEnumerable<string> input)
{
var heights = from line in input.Indexed()
from c in line.Value.Indexed()
select new { Point = new Point(c.Index, line.Index), Height = c.Value };
_map = heights.ToDictionary(x => x.Point, x => x.Height);
_start = heights.First(x => x.Height == StartMarker).Point;
_end = heights.First(x => x.Height == EndMarker).Point;
_distances = new Dictionary<Point, int> { [_end] = 0 };
var queue = new Queue<Point>();
queue.Enqueue(_end);
while (queue.TryDequeue(out var point))
{
var neighbours = from neighbour in GetNeighbours(point)
where _map.ContainsKey(neighbour)
where !_distances.ContainsKey(neighbour)
where GetHeight(_map[point]) - GetHeight(_map[neighbour]) <= 1
select neighbour;
foreach (var neighbour in neighbours)
{
_distances[neighbour] = _distances[point] + 1;
queue.Enqueue(neighbour);
}
}
}
private static int GetHeight(char c) => c switch
{
StartMarker => 0,
EndMarker => MaxHeight - MinHeight,
_ => c - MinHeight,
};
public int PartOne()
{
return _distances[_start];
}
public int PartTwo()
{
return _distances.Where(x => _map[x.Key] == MinHeight).Min(x => x.Value);
}
private record struct Point(int X, int Y);
private static IEnumerable<Point> GetNeighbours(Point point)
{
yield return new Point(point.X + 1, point.Y);
yield return new Point(point.X - 1, point.Y);
yield return new Point(point.X, point.Y + 1);
yield return new Point(point.X, point.Y - 1);
}
}
public class Day12Test
{
private const string InputFile = "Day12.Input.txt";
private const string ExampleFile = "Day12.Example.txt";
[Theory]
[FileData(ExampleFile, FileContents.StringPerLine, 31)]
[FileData(InputFile, FileContents.StringPerLine, 330)]
public void TestPartOne(IEnumerable<string> input, int expected)
{
var solution = new Day12(input);
Assert.Equal(expected, solution.PartOne());
}
[Theory]
[FileData(ExampleFile, FileContents.StringPerLine, 29)]
[FileData(InputFile, FileContents.StringPerLine, 321)]
public void TestPartTwo(IEnumerable<string> input, int expected)
{
var solution = new Day12(input);
Assert.Equal(expected, solution.PartTwo());
}
}