Add day 12
This commit is contained in:
327
Days/Day12.cs
Normal file
327
Days/Day12.cs
Normal file
@@ -0,0 +1,327 @@
|
||||
using Spectre.Console;
|
||||
|
||||
namespace AdventOfCode.Days;
|
||||
|
||||
public class Day12 : Day
|
||||
{
|
||||
public override int Number => 12;
|
||||
public override string Name => "Hill Climbing Algorithm";
|
||||
|
||||
public const int EndElevation = 25;
|
||||
|
||||
// Color map of elevation: blue -> green -> yellow -> orange -> red
|
||||
private readonly Color[] _colorMap =
|
||||
{
|
||||
Color.Blue1,
|
||||
Color.DodgerBlue1,
|
||||
Color.DeepSkyBlue1,
|
||||
Color.Turquoise2,
|
||||
Color.Cyan1,
|
||||
Color.Cyan2,
|
||||
Color.MediumSpringGreen,
|
||||
Color.SpringGreen1,
|
||||
Color.SpringGreen2_1,
|
||||
Color.Green1,
|
||||
Color.DarkOliveGreen2,
|
||||
Color.GreenYellow,
|
||||
Color.DarkOliveGreen1,
|
||||
Color.Yellow2,
|
||||
Color.Khaki1,
|
||||
Color.Yellow1,
|
||||
Color.NavajoWhite1,
|
||||
Color.LightGoldenrod2_1,
|
||||
Color.Gold1,
|
||||
Color.SandyBrown,
|
||||
Color.Orange1,
|
||||
Color.DarkOrange,
|
||||
Color.OrangeRed1,
|
||||
Color.IndianRed1,
|
||||
Color.HotPink,
|
||||
Color.MediumOrchid1_1
|
||||
};
|
||||
|
||||
private (int x, int y) _end;
|
||||
private (int x, int y) _start;
|
||||
|
||||
public override void RunPart1()
|
||||
{
|
||||
var map = ParseMap();
|
||||
var canvas = DrawMap(map);
|
||||
|
||||
// Test all possible solutions
|
||||
var minimumPathLength = ExplorePath(map);
|
||||
|
||||
// Draw solution path
|
||||
foreach (var (x, y) in minimumPathLength.path)
|
||||
{
|
||||
canvas.SetPixel(x, y, Color.White);
|
||||
}
|
||||
|
||||
AnsiConsole.Write(canvas);
|
||||
AnsiConsole.WriteLine();
|
||||
|
||||
AnsiConsole.MarkupLine($"[green]Minimum path length: [yellow]{minimumPathLength.length}[/][/]");
|
||||
}
|
||||
|
||||
public override void RunPart2()
|
||||
{
|
||||
var map = ParseMap();
|
||||
var canvas = DrawMap(map);
|
||||
|
||||
// Test all possible solutions
|
||||
var minimumPathLength = FindNearestStart(map);
|
||||
|
||||
// Draw solution path
|
||||
foreach (var (x, y) in minimumPathLength.path)
|
||||
{
|
||||
canvas.SetPixel(x, y, Color.White);
|
||||
}
|
||||
|
||||
AnsiConsole.Write(canvas);
|
||||
AnsiConsole.WriteLine();
|
||||
|
||||
AnsiConsole.MarkupLine($"[green]Minimum path length: [yellow]{minimumPathLength.length}[/][/]");
|
||||
}
|
||||
|
||||
private (int length, List<(int x, int y)> path) ExplorePath(byte[,] map)
|
||||
{
|
||||
var height = map.GetLength(0);
|
||||
var width = map.GetLength(1);
|
||||
|
||||
// Store seen positions with number of steps to reach this position
|
||||
var exploredPositions = new Dictionary<(int x, int y), int>();
|
||||
var toExplore = new Queue<(int x, int y, int elevation, int steps, List<(int x, int y)> path)>();
|
||||
var pathLengths = new List<(int length, List<(int x, int y)> path)>();
|
||||
|
||||
toExplore.Enqueue((_start.x, _start.y, 0, 0, new()));
|
||||
|
||||
// Explore all possible path
|
||||
while (toExplore.Count > 0)
|
||||
{
|
||||
var (x, y, previousElevation, steps, path) = toExplore.Dequeue();
|
||||
|
||||
// If we went out of bound
|
||||
if (x < 0 || x >= width || y < 0 || y >= height)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If new elevation is too high
|
||||
var newElevation = map[y, x];
|
||||
if (newElevation - previousElevation > 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If new path is not better than old path, just skip
|
||||
if (exploredPositions.TryGetValue((x, y), out var oldSteps))
|
||||
{
|
||||
if (oldSteps <= steps)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark this position as explored and store required number of steps to reach it
|
||||
exploredPositions[(x, y)] = steps;
|
||||
|
||||
// Update path
|
||||
var newPath = new List<(int x, int y)>(path) { (x, y) };
|
||||
|
||||
// If we found the end, note that we could end the search here since it's a bfs, there can't be
|
||||
// any shorter path to this point
|
||||
if ((x, y) == _end)
|
||||
{
|
||||
pathLengths.Add((steps, newPath));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var nextPositions = new (int x, int y)[]
|
||||
{
|
||||
(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)
|
||||
};
|
||||
|
||||
foreach (var nextPosition in nextPositions)
|
||||
{
|
||||
toExplore.Enqueue((nextPosition.x, nextPosition.y, newElevation, steps + 1, newPath));
|
||||
}
|
||||
}
|
||||
|
||||
return pathLengths.MinBy(p => p.length);
|
||||
}
|
||||
|
||||
private (int length, List<(int x, int y)> path) FindNearestStart(byte[,] map)
|
||||
{
|
||||
var height = map.GetLength(0);
|
||||
var width = map.GetLength(1);
|
||||
|
||||
// Store seen positions with number of steps to reach this position
|
||||
var exploredPositions = new Dictionary<(int x, int y), int>();
|
||||
var toExplore = new Queue<(int x, int y, int elevation, int steps, List<(int x, int y)> path)>();
|
||||
var pathLengths = new List<(int length, List<(int x, int y)> path)>();
|
||||
|
||||
toExplore.Enqueue((_end.x, _end.y, EndElevation, 0, new()));
|
||||
|
||||
// Explore all possible path
|
||||
while (toExplore.Count > 0)
|
||||
{
|
||||
var (x, y, previousElevation, steps, path) = toExplore.Dequeue();
|
||||
|
||||
// If we went out of bound
|
||||
if (x < 0 || x >= width || y < 0 || y >= height)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If new elevation is too low, skip
|
||||
var newElevation = map[y, x];
|
||||
if (previousElevation - newElevation > 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If new path is not better than old path, just skip
|
||||
if (exploredPositions.TryGetValue((x, y), out var oldSteps))
|
||||
{
|
||||
if (oldSteps <= steps)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark this position as explored and store required number of steps to reach it
|
||||
exploredPositions[(x, y)] = steps;
|
||||
|
||||
// Update path
|
||||
var newPath = new List<(int x, int y)>(path) { (x, y) };
|
||||
|
||||
// If we found a possible start, same as in the 1st part, we could stop here
|
||||
if (newElevation == 0)
|
||||
{
|
||||
pathLengths.Add((steps, newPath));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var nextPositions = new (int x, int y)[]
|
||||
{
|
||||
(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)
|
||||
};
|
||||
|
||||
foreach (var nextPosition in nextPositions)
|
||||
{
|
||||
toExplore.Enqueue((nextPosition.x, nextPosition.y, newElevation, steps + 1, newPath));
|
||||
}
|
||||
}
|
||||
|
||||
return pathLengths.MinBy(p => p.length);
|
||||
}
|
||||
|
||||
private byte[,] ParseMap()
|
||||
{
|
||||
var lines = Input.ReadAllLines().ToArray();
|
||||
var lineCount = lines.Length;
|
||||
var columnCount = lines[0].Length;
|
||||
|
||||
var map = new byte[lineCount, columnCount];
|
||||
|
||||
for (int i = 0; i < lineCount; i++)
|
||||
{
|
||||
var line = lines[i];
|
||||
|
||||
for (int j = 0; j < columnCount; j++)
|
||||
{
|
||||
var elevation = line[j];
|
||||
|
||||
map[i, j] = elevation switch
|
||||
{
|
||||
'S' => 0,
|
||||
'E' => EndElevation,
|
||||
_ => (byte) (elevation - 'a')
|
||||
};
|
||||
|
||||
// Store the end
|
||||
if (elevation == 'E')
|
||||
{
|
||||
_end = (j, i);
|
||||
}
|
||||
|
||||
// Store the start
|
||||
if (elevation == 'S')
|
||||
{
|
||||
_start = (j, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private Canvas DrawMap(byte[,] map)
|
||||
{
|
||||
var height = map.GetLength(0);
|
||||
var width = map.GetLength(1);
|
||||
|
||||
var canvas = new Canvas(width, height);
|
||||
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
canvas.SetPixel(x, y, _colorMap[map[y, x]]);
|
||||
}
|
||||
}
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
#region Input
|
||||
|
||||
public const string Input =
|
||||
"""
|
||||
abccccccaaccaaccccaaaaacccccaaaaccccccccccccccccccccccccccccccccaaaaaaaaaaaaaaaaaaaccccccccccccccccaaaccccccccccccaacccccccccccccccccccccccccccccccccccccccccaaaa
|
||||
abaaaaccaaaaaccccaaaaaccccccaaaaccccccccccccccccccccaaacccccccccccaaaaaaaaaaaaaaaaaaccccccccccccccccaaaaccccccaaacaaccccccccccccccccccccccccccccccccccccccccaaaaa
|
||||
abaaacccaaaaaaaacaaaaaacccccaaaaccccccccccccccccccccaaaaacccccccccaaaaaaaaaaaaaaaaacccccccccaaccccaaaaaacccccccaaaaaccccaaccccccccccccccacccccccccccccccccccaaaaa
|
||||
abaaacccccaaaaaccccaaaaccccccaaacccccccccccccccccccaaaaaccccccccccaaaaaacacaaaaaacccccccccccaaccccaaaaacccccccccaaaaaaccaaaaaaccccccccccaaaccccacccccccccccaaaaaa
|
||||
abaacccccaaaaaccccaacccccccccccccccaaaaacccccccccccaaaaacccccccccaaaaaaaaccaaaaaaacccccccaaaaaaaaccaaaaacccccccaaaaaaaccaaaaacccccccccccaaacccaaaccccccccccccccaa
|
||||
abaaacccaaacaacccccccccccccccccccccaaaaaccccccccccccaaaaacccccccaaaaaaaaaccaaccaaacccccccaaaaaaaaccaacccccccccaaaaaaccaaaaaaccccccccccccaaaacaaaaccccccccccccccaa
|
||||
abaaacccccccaaccccccccccccccccccccaaaaaaccccccccccccaaccccccaacccaaaccaaaaccccccaacccccccccaaaacccccccccccccccaacaaaccaaaaaaaccccccccccccajjjjjjjcccccccccccccccc
|
||||
abcaacccccccccccccccccccccccccccccaaaaaaccccccccccccccccccccaaaaccccccaaaaccccccccccccccaacaaaaaccccccccccccccccccaaccccaaaaaacccccccccccjjjjjjjjjcccccaaaccccccc
|
||||
abccccccccccccccccccccccccccccccccaaaaaaccaaccccccccccccccaaaaaacccccccaaacccccccccccaacaaaaaaaaccccccccccccccccccccccccaaccaaccccccccaiijjjjojjjjcccccaaacaccccc
|
||||
abcccccccccccccccccccccccaaacccccccaaacacaaacccccccccccccccaaaaccccaaccccccccccccccccaaaaaaacccaccccccccccccccccccccccccaacccccccccccaiiijjooooojjkccaaaaaaaacccc
|
||||
abccccccccccccccccccccccaaaaccccccccccaaaaaccccccccccccccccaaaaacccaaaaaccccccccccccccaaaaaacccccccccccccccccccccccccccccccccccccciiiiiiiioooooookkkcaaaaaaaacccc
|
||||
abccccccccccccccccccccccaaaaccccccccccaaaaaaaacccccccccccccaacaaccaaaaacccccccaaacccaaaaaaaaccccccccccccccccccccccccccccccccccchiiiiiiiiooooouoookkkccaaaaaaccccc
|
||||
abcccccccccaaccccccccccccaaaccccccccccccaaaaacccccccccccccccccccccaaaaaccccccaaaacccaaaaacaacccccccccccccaacaacccccccccccccccchhhiiiinnnooouuuuoookkkccaaaaaccccc
|
||||
abcccccccccaaacccccccccccccccccccccccccaaaaacccccccccccccccccccccccaaaaacccccaaaaccccccaaccccccccccccccccaaaaacccccccccccccccchhhnnnnnnnnouuuuuuppkkkkaaaaaaccccc
|
||||
abccccccaaaaaaaacccaaccccccccccccccccccaacaaccaacaaccccccccccccccccaacccccccccaaaccccccaacccccccccccccccaaaaacccccccccccccccchhhnnnnnnnnntuuxuuupppkkkkkacccccccc
|
||||
abccccccaaaaaaaacacaaaacccccccccccccccccccaaccaaaaacccccccccccccccccccccccccccccccccccccccccccccccccccccaaaaaacccccccaacccccchhhnnnnttttttuxxxuuppppkkkkkcccccccc
|
||||
abcccccccaaaaaaccaaaaaaccccccccccaaccccccccccaaaaaccccccccccccccccccccccccaaacccccccccccccccccccccccccccccaaaaccaaccaaacccaaahhhnnntttttttuxxxxuupppppllllccccccc
|
||||
abcccccccaaaaaacccaaaacccccccccaaaaaaccccccccaaaaaacccccccccccccccccccccccaaacccccccccccccccccccccccccccccacccccaaaaaaacaaaaahhhppntttxxxxxxxxuuuuvpppplllccccccc
|
||||
abcccccccaaaaaacccaaaacccccccccaaaaaacccccaaaaaaaaaccccccccccccccccccccaaaaaaaacccccccccccccccccccccaaaccccccaacaaaaaaccaaaaahhhpppttxxxxxxxxyuuvvvvvppplllcccccc
|
||||
abcccccccaaccaacccaacaccaaaaccccaaaaacccccaaaaaaaaaccccccccccccccccccccaaaaaaaacccccccccccccccccccccaaacaaaaaaaccaaaaaaaaaaaaahhppptttxxxxxxyyyyyyvvvppplllcccccc
|
||||
SbccccccccccccccccccccccaaaacccaaaaacccccccaaaaaaaaacaaaccccccccaacccccccaaaaaccccccccaaaaacccccccccaaaaaaaaaaaaaaaaaaaaaaaaacgggpppttxxxxEzzyyyyyvvvqqqlllcccccc
|
||||
abccccccccccccccccccccccaaaacccaaaaacccccccaaaaaaaaccaaaccccccccaaacaaccaaaaaaccccccccaaaaacccccccaaaaaaaaaaaaaaaaaaaaaaaaaaacgggpppsssxxxyyyyyyvvvvvqqlllccccccc
|
||||
abcccaaaccccccccccccccccaaaccccccccccccccccaaaaaaaaaaaaaccccccccaaaaaaccaaaaaacccccccaaaaaacccaaaccaaaaaccaaaaaaaaaaaacccccccccgggppssswwyyyyyyvvvvqqqqlllccccccc
|
||||
abcaaaaaccccccccccccccccccccccccccccccccccaaaaaaaaaaaaacccccccaaaaaaacccaccaaacccccccaaaaaacccaaacccaaaaaaaaaaaccccaaacccaaaaacgggppsswwwyyyyyyvvqqqqqlllcccccccc
|
||||
abcaaaaaaccccccccccccccccccccccccccccccccccaaccaaaaaaaaaaaccccaaaaaaacccccccccccccccccaaaaacccaaacaaaacaaaaaaaaccccaaacccaaaaacggpppsswwwywwyyyvvqqqmmmlccccccccc
|
||||
abcaaaaaacccccccaacaaccccccccccccccccccccccccccaaaaaaaaaaaccccccaaaaacccccccccccccccccaaaccaaaaaaaaaaacccccccaacccccccccaaaaaacggpppsswwwwwwwwyvvqqqmmmcccccccccc
|
||||
abcaaaaaccccccccaaaaaccccccccccccccccccccccccccccaaaaaaaacccccccaacaaacccccccccccccccccccccaaaaaaaaaccccccccccccccccccccaaaaaagggoossswwwwrrwwwvvqqmmmccccccccccc
|
||||
abcaaaaacccccccaaaaaccccccccccccccccccccccccccccaaaaaaacccccccccaaccccccccccccccccccccccccccaaaaaaacccccccccccaaaccccccccaaaaagggooosssssrrrrwwwvqqmmmcccaacccccc
|
||||
abcccccccccccccaaaaaaccccccccccccccccccccaacccccccccaaaccccccccccccccccccccccccccccccccccccccaaaaaaccccccccccccaaaaccccccaaaccgggooosssssrrrrrwwrrqmmmcccaacccccc
|
||||
abcccccccccccccccaaaacccccccccccccccccccaaaacccccccacaaacccccccccccccccccccccccccccccccccccccaaaaaaacccccccccaaaaaacccccccccccgffoooooosoonrrrrrrrrmmmccaaaaacccc
|
||||
abcccccccccccccccaccccccccccccccccccccccaaaacccccccaaaaacccccccccccccccccccccccccccccccccccccaaacaaacccccccccaaaaacccccccccccccfffoooooooonnnrrrrrmmmddcaaaaacccc
|
||||
abccccccccccccccccccccccccccccccccccccccaaaaccccccccaaaaacccccccccccccccccccccccccaaaccccccccaacccccccccccccccaaaaaccccccccccccffffoooooonnnnnnrnnmmmdddaaaaacccc
|
||||
abcccccccccccccccccccccccccccccccccccccccccccccccccaaaaaacccccccccccccccccaaaaaccaaaacccccccccccccccccccccccccaacccccccccccccccfffffffffeeeennnnnnmmdddaaaacccccc
|
||||
abcccccccaaaccccccccaccccccccccccccccccccccccccccccaaaaccccccccccccaaaccccaaaaaccaaaaccccccccccccccccccccccccccccccccccccccccccccfffffffeeeeennnnnmddddaaaaaccccc
|
||||
abcccaaccaaacccccaaaacccccaacccccccccccccccccccccccccaaacccccccccccaaacccaaaaaacccaaaccccccccccccccccccccccccccccccccccccccccccccccffffeeeeeeeedddddddcccaacccccc
|
||||
abcccaaaaaaacccccaaaaaaccaaacccccccccccccccccccccccccccacccccccccccaaaaccaaaaaaccccccccccccccccccccccccccaacccccccccaaaccccccccccccccaaaaaaeeeeedddddcccccccccccc
|
||||
abcccaaaaaacccccccaaaacccaaacaaaccccaaaacccccccccaaacaaaccccccaacccaaaacaaaaaaacccccccccccccccccccccccccaaaccccccccaaaacccccccccccccccccccaaaaeeddddccccccccccccc
|
||||
abccccaaaaaaaacccaaaaaaaaaaaaaaaccccaaaacccccccccaaaaaaacccccaaacccaaaaaaaaaacccccccccccccccccccccccaaacaaaccccccccaaaaccccccccccccccccccccaaaccccccccccccccaaaca
|
||||
abcccaaaaaaaaacccaacaaaaaaaaaaacccccaaaaccccccccccaaaaaacaaacaaacaaaaaaaaaacccccccccccccccaaacccccccaaaaaaaaaaccccccaaaccccccccccccccccccccaacccccccccccccccaaaaa
|
||||
abcccaaaaaaaacccccccccccaaaaaacccccccaacccccccccccaaaaaaaaaaaaaaaaaaaaaaaaccccccccccccccccaaaacccccccaaaaaaaaacccccccccccccccccccccccccccccaaacccccccccccccccaaaa
|
||||
abccaaaaaaacccccccccccccaaaaaaacccccccccccccccccaaaaaaaaaaaaaaaaaaaaaaaaaaacccccccccccccccaaaacccccccaaaaaaaacccccccccccccccccccccccccccccccccccccccccccccccaaaaa
|
||||
""";
|
||||
|
||||
#endregion
|
||||
}
|
||||
BIN
Preview.png
BIN
Preview.png
Binary file not shown.
|
Before Width: | Height: | Size: 124 KiB |
BIN
Preview.webp
Normal file
BIN
Preview.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
Reference in New Issue
Block a user