2024-12-10 14:30:51 +02:00
|
|
|
|
var rawTopographicMap = File.ReadLines("input.txt");
|
|
|
|
|
|
var topographicMap = CreateTopographicMap(rawTopographicMap);
|
|
|
|
|
|
|
|
|
|
|
|
var availableDirections = new List<(int, int)>()
|
|
|
|
|
|
{
|
|
|
|
|
|
(-1, 0), // Up
|
|
|
|
|
|
(1, 0), // Down
|
|
|
|
|
|
(0, -1), // Left
|
|
|
|
|
|
(0, 1) // Right
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Console.WriteLine($"Part1: {Part1(topographicMap, availableDirections)}\nPart2: {Part2(topographicMap, availableDirections)}");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int Part2(int[,] mapInput, List<(int, int)> directions)
|
|
|
|
|
|
{
|
|
|
|
|
|
var totalRating = 0;
|
|
|
|
|
|
for (var r = 0; r < mapInput.GetLength(0); r++)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (var c = 0; c < mapInput.GetLength(1); c++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (mapInput[r, c] == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
totalRating += FindDistinctTrails(r, c, mapInput, directions);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return totalRating;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-10 14:37:56 +02:00
|
|
|
|
// Could reuse the trailHead method with minor edits
|
2024-12-10 14:30:51 +02:00
|
|
|
|
int FindDistinctTrails(int r, int c, int[,] mapInput, List<(int, int)> directions)
|
|
|
|
|
|
{
|
|
|
|
|
|
var stack = new Stack<List<(int, int)>>();
|
|
|
|
|
|
stack.Push(new List<(int, int)> { (r, c) });
|
|
|
|
|
|
var trails = 0;
|
|
|
|
|
|
|
|
|
|
|
|
while (stack.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var currentPath = stack.Pop();
|
|
|
|
|
|
var (cr, cc) = currentPath[^1];
|
|
|
|
|
|
|
|
|
|
|
|
if (mapInput[cr, cc] == 9)
|
|
|
|
|
|
{
|
|
|
|
|
|
trails++;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var (dr, dc) in directions)
|
|
|
|
|
|
{
|
|
|
|
|
|
var nr = cr + dr;
|
|
|
|
|
|
var nc = cc + dc;
|
|
|
|
|
|
|
|
|
|
|
|
if (nr >= 0 && nr < mapInput.GetLength(0) && nc >= 0 && nc < mapInput.GetLength(1) &&
|
|
|
|
|
|
mapInput[nr, nc] == mapInput[cr, cc] + 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
var nextPath = new List<(int, int)>(currentPath);
|
|
|
|
|
|
nextPath.Add((nr, nc));
|
|
|
|
|
|
stack.Push(nextPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return trails;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int Part1(int[,] map, List<(int, int)> directions)
|
|
|
|
|
|
{
|
|
|
|
|
|
var totalScore = 0;
|
|
|
|
|
|
|
|
|
|
|
|
for (var row = 0; row < map.GetLength(0); row++)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (var column = 0; column < map.GetLength(1); column++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (map[row, column] == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
totalScore += TrailHead(row, column, map, directions);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return totalScore;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int TrailHead(int startRow, int startColumn, int[,] map, List<(int, int)> directions)
|
|
|
|
|
|
{
|
|
|
|
|
|
var rows = map.GetLength(0);
|
|
|
|
|
|
var cols = map.GetLength(1);
|
|
|
|
|
|
var queue = new Queue<(int, int)>();
|
|
|
|
|
|
var visited = new HashSet<(int, int)>();
|
|
|
|
|
|
var reachableNines = new HashSet<(int, int)>();
|
|
|
|
|
|
|
|
|
|
|
|
queue.Enqueue((startRow, startColumn));
|
|
|
|
|
|
|
|
|
|
|
|
while (queue.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var (r, c) = queue.Dequeue();
|
|
|
|
|
|
|
|
|
|
|
|
if (visited.Contains((r, c)))
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
visited.Add((r, c));
|
|
|
|
|
|
|
|
|
|
|
|
if (map[r, c] == 9)
|
|
|
|
|
|
{
|
|
|
|
|
|
reachableNines.Add((r, c));
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var dir in directions)
|
|
|
|
|
|
{
|
|
|
|
|
|
var nr = r + dir.Item1;
|
|
|
|
|
|
var nc = c + dir.Item2;
|
|
|
|
|
|
|
|
|
|
|
|
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (map[nr, nc] == map[r, c] + 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
queue.Enqueue((nr, nc));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return reachableNines.Count;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int[,] CreateTopographicMap(IEnumerable<string> lines)
|
|
|
|
|
|
{
|
|
|
|
|
|
var lineList = lines.Select(line => line.Trim()).ToList();
|
|
|
|
|
|
var map = new int[lineList.Count, lineList[0].Length];
|
|
|
|
|
|
|
|
|
|
|
|
for (var r = 0; r < map.GetLength(0); r++)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (var c = 0; c < map.GetLength(1); c++)
|
|
|
|
|
|
{
|
|
|
|
|
|
map[r, c] = lineList[r][c] - '0';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return map;
|
|
|
|
|
|
}
|