/
Day12c.cs
111 lines (91 loc) · 3.93 KB
/
Day12c.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
namespace xmas.DayTwelve
{
public record Grid(IEnumerable<(int x, int y, char height, int weight)> Nodes)
{
public (int x, int y, char height, int weight) this[int x, int y] => this.Nodes.SingleOrDefault(n => n.x == x && n.y == y);
}
public record Queue
{
public IEnumerable<(int x, int y, char height, int weight)> CurrentQueue { get; set; }
public IEnumerable<(int x, int y, char height, int weight)> AlreadySeen { get; set; }
}
public class Day12b
{
public static int ClimbingValue(char c) => c switch
{
'S' => 0,
'E' => 26,
_ => c - 96
};
public static bool IsClimbable(char from, char to) =>
ClimbingValue(from) - ClimbingValue(to) <= 1;
public static Grid ParseGrid(string input) =>
input.Split(new[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries)
.SelectMany((y, yI) =>
y.Select((x, xI) => (xI, yI, x, x == 'S' ? 1 : -1))
).Bind(x => new Grid(x));
public static int CalculateStepsToPoint(string input, char beginning = 'S', char destination = 'E')
{
var grid = ParseGrid(input).Nodes.ToArray();
var start = grid.Single(x => x.height == destination);
var initialQueue = new Queue
{
CurrentQueue = new[] { (start.x, start.y, start.height, 0) },
AlreadySeen = new[] { (start.x, start.y, start.height, 0) }
};
var finalQueue = initialQueue.IterateUntil(x => x.AlreadySeen.Any(y => y.height == beginning) || !x.CurrentQueue.Any(),
q =>
{
var currentItem = q.CurrentQueue.FirstOrDefault();
var neighbours = new[]
{
grid.SingleOrDefault(x => x.x == currentItem.x + 1 && x.y == currentItem.y),
grid.SingleOrDefault(x => x.x == currentItem.x - 1 && x.y == currentItem.y),
grid.SingleOrDefault(x => x.x == currentItem.x && x.y == currentItem.y + 1),
grid.SingleOrDefault(x => x.x == currentItem.x && x.y == currentItem.y - 1),
}.ToArray();
var neighboursToAdd = neighbours.Where(n =>
n != default && IsClimbable(currentItem.height, n.height) &&
!q.AlreadySeen.Any(z => z.x == n.x && z.y == n.y))
.Select(x => (x.x, x.y, x.height, currentItem.weight + 1))
.ToArray();
var newQ = new Queue
{
CurrentQueue = q.CurrentQueue.Skip(1).Concat(neighboursToAdd).ToArray(),
AlreadySeen = q.AlreadySeen.Concat(neighboursToAdd).ToArray()
};
return newQ;
});
return finalQueue.AlreadySeen.Where(x => x.height == beginning).Min().weight;
}
[Fact]
public void Test01()
{
const string input = "Sabqponm\r\nabcryxxl\r\naccszExk\r\nacctuvwj\r\nabdefghi";
var result = CalculateStepsToPoint(input);
result.Should().Be(31);
}
[Fact]
public void Day12_PartA()
{
var input = File.ReadAllText("./Day12.txt");
var result = CalculateStepsToPoint(input);
result.Should().Be(425);
}
[Fact]
public void Test02()
{
const string input = "Sabqponm\r\nabcryxxl\r\naccszExk\r\nacctuvwj\r\nabdefghi";
var result = CalculateStepsToPoint(input, 'a');
result.Should().Be(29);
}
[Fact]
public void Day12_PartB()
{
var input = File.ReadAllText("./Day12.txt");
var result = CalculateStepsToPoint(input, 'a');
result.Should().Be(418);
}
}
}