generated from mazharenko/aoc-agent-template-multipleyears
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay12.cs
158 lines (137 loc) · 3.64 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
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
using aoc.Common;
using aoc.Common.Search;
using MoreLinq;
namespace aoc.Year2024;
internal partial class Day12
{
private readonly Example example = new(
"""
RRRRIICCFF
RRRRIICCCF
VVRRRCCFFF
VVRCCCJFFF
VVVVCJJCFE
VVIVCCJJEE
VVIIICJJEE
MIIIIIJJEE
MIIISIJEEE
MMMISSJEEE
""");
public char[,] Parse(string input)
{
return Character.Letter.Map().Parse(input);
}
internal partial class Part1
{
public int Solve(char[,] input)
{
var remainingPlots = input.AsEnumerable().Select(x => x.point).ToHashSet();
var price = 0;
while (remainingPlots.Count != 0)
{
var start = remainingPlots.First();
// While traversing the graph, for each visited node, we not only determine its adjacent nodes
// but also count how many of them lie outside this region.
var region = Dijkstra.StartWith((plot: start, plant: input.At(start), sides: (int?)null))
.WithAdjacency(p =>
{
var dirs = Directions.All4();
var allAdj = dirs.Select(d => d + p.plot).ToList();
var (inside, outside) =
allAdj.Partition(adj => input.TryAt(adj, out var adjValue) && adjValue == p.plant);
return inside.Select(x => (x, input.At(x), (int?)null))
.Append((p.plot, p.plant, outside.Count()));
}).Items()
.Where(x => x.sides is not null)
.Select(x => (x.plot, sides: x.sides!.Value))
.ToList();
var area = region.Select(x => x.plot).Count();
var perimeter = region.Sum(x => x.sides);
price += area * perimeter;
remainingPlots.ExceptWith(region.Select(x => x.plot));
}
return price;
}
}
internal partial class Part2
{
public Part2()
{
Expect(example, 1206);
}
private readonly Example example1 = new(
"""
EEEEE
EXXXX
EEEEE
EXXXX
EEEEE
""", 236);
private readonly Example example2 = new(
"""
AAAAAA
AAABBA
AAABBA
ABBAAA
ABBAAA
AAAAAA
""", 368);
private readonly Example example3 = new(
"""
AAAA
BBCD
BBCC
EEEC
""", 80);
public int Solve(char[,] input)
{
var remainingPoints = input.AsEnumerable().ToHashSet();
var price = 0;
while (remainingPoints.Count != 0)
{
var start = remainingPoints.First().point;
var region = Dijkstra.StartWith(start)
.WithAdjacency(p =>
{
var dirs = Directions.All4();
return dirs.Select(d => d + p)
.Where(adj => input.TryAt(adj, out var adjValue)
&& adjValue == input.At(p));
})
.Items().ToList();
var area = region.Count;
var extendedRegion =
region.SelectMany(x => Directions.All8().Append(V<int>.Zero).Select(d => d + x))
.Distinct().ToList();
// Counting corners instead of sides
// Scanning the region with a 2x2 window to determine how many corners are in it by counting the plots.
var corners = extendedRegion
.Sum(x =>
{
//
// X .
// . .
//
var blockToFindCorner = new[] { x, Directions.W + x, Directions.S + x, Directions.SW + x };
var pointsFoundInBlock = blockToFindCorner.Where(l => region.Contains(l)).ToList();
return pointsFoundInBlock switch
{
// A . . . . . . A A A A . . A A A
// . . A . . A . . A . A A A A . A
{ Count: 1 or 3 } => 1,
// A . . A
// . A A .
[var found1, var found2] when found1.MDist(found2) == 2 => 2,
// A A A A . A . . A . . .
// A A . . . A A A A . . .
_ => 0
};
});
var sides = corners;
price += area * sides;
remainingPoints = remainingPoints.ExceptBy(region, x => x.point).ToHashSet();
}
return price;
}
}
}