169 lines
4.3 KiB
C#
169 lines
4.3 KiB
C#
using System.Collections.Frozen;
|
|
using System.Numerics;
|
|
using Spectre.Console;
|
|
|
|
namespace AdventOfCode.Days;
|
|
|
|
public class Day10 : Day
|
|
{
|
|
public override int Number => 10;
|
|
public override string Name => "Hoof It";
|
|
|
|
private const int MapSize = 60;
|
|
|
|
public override void RunPart1(bool display = true)
|
|
{
|
|
var hikingTrailsScores = 0;
|
|
|
|
var (heightMap, trailHeads) = ParseMap();
|
|
|
|
var hikingTrails = new HashSet<Point>();
|
|
|
|
foreach (var trailHead in trailHeads)
|
|
{
|
|
hikingTrails.Clear();
|
|
|
|
GetHikingTrailScore(trailHead, -1);
|
|
|
|
hikingTrailsScores += hikingTrails.Count;
|
|
}
|
|
|
|
if (display)
|
|
{
|
|
AnsiConsole.MarkupLine($"[green]Sum of scores of hiking trails: [yellow]{hikingTrailsScores}[/][/]");
|
|
}
|
|
|
|
return;
|
|
|
|
void GetHikingTrailScore(Point position, int previousHeight)
|
|
{
|
|
// Out of bounds
|
|
if (position is { X: < 0 or >= MapSize } or { Y: < 0 or >= MapSize })
|
|
{
|
|
return;
|
|
}
|
|
|
|
var height = heightMap[position.X, position.Y];
|
|
|
|
if (height - previousHeight is not 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (height == 9)
|
|
{
|
|
hikingTrails.Add(position);
|
|
}
|
|
|
|
|
|
GetHikingTrailScore(position + (1, 0), height);
|
|
GetHikingTrailScore(position + (-1, 0), height);
|
|
GetHikingTrailScore(position + (0, 1), height);
|
|
GetHikingTrailScore(position + (0, -1), height);
|
|
}
|
|
}
|
|
|
|
public override void RunPart2(bool display = true)
|
|
{
|
|
var (heightMap, trailHeads) = ParseMap();
|
|
|
|
var totalRating = 0;
|
|
|
|
foreach (var trailHead in trailHeads)
|
|
{
|
|
GetHikingTrailRating(trailHead, -1);
|
|
}
|
|
|
|
if (display)
|
|
{
|
|
AnsiConsole.MarkupLine($"[green]Total rating of hiking trails: [yellow]{totalRating}[/][/]");
|
|
}
|
|
|
|
return;
|
|
|
|
void GetHikingTrailRating(Point position, int previousHeight)
|
|
{
|
|
// Out of bounds
|
|
if (position is { X: < 0 or >= MapSize } or { Y: < 0 or >= MapSize })
|
|
{
|
|
return;
|
|
}
|
|
|
|
var height = heightMap[position.X, position.Y];
|
|
|
|
if (height - previousHeight is not 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (height == 9)
|
|
{
|
|
totalRating++;
|
|
}
|
|
|
|
GetHikingTrailRating(position + (1, 0), height);
|
|
GetHikingTrailRating(position + (-1, 0), height);
|
|
GetHikingTrailRating(position + (0, 1), height);
|
|
GetHikingTrailRating(position + (0, -1), height);
|
|
}
|
|
}
|
|
|
|
private (byte[,] HeightMap, List<Point> TrailHeads) ParseMap()
|
|
{
|
|
var heightMap = new byte[MapSize, MapSize];
|
|
var trailHeads = new List<Point>();
|
|
|
|
var y = 0;
|
|
foreach (var line in Input.AsSpan().EnumerateLines())
|
|
{
|
|
var x = 0;
|
|
foreach (var height in line)
|
|
{
|
|
var heightValue = height - '0';
|
|
|
|
if (heightValue is 0)
|
|
{
|
|
trailHeads.Add(new Point(x, y));
|
|
}
|
|
|
|
heightMap[x, y] = (byte)heightValue;
|
|
|
|
x++;
|
|
}
|
|
|
|
y++;
|
|
}
|
|
|
|
return (heightMap, trailHeads);
|
|
}
|
|
|
|
|
|
private readonly record struct Point(int X, int Y)
|
|
: IAdditionOperators<Point, Point, Point>,
|
|
ISubtractionOperators<Point, Point, Point>,
|
|
IMultiplyOperators<Point, int, Point>
|
|
{
|
|
public static Point operator +(Point left, Point right)
|
|
{
|
|
return new Point(left.X + right.X, left.Y + right.Y);
|
|
}
|
|
|
|
public static Point operator -(Point left, Point right)
|
|
{
|
|
return new Point(left.X - right.X, left.Y - right.Y);
|
|
}
|
|
|
|
public static Point operator *(Point left, int right)
|
|
{
|
|
return new Point(left.X * right, left.Y * right);
|
|
}
|
|
|
|
public static Point operator *(int left, Point right)
|
|
{
|
|
return new Point(right.X * left, right.Y * left);
|
|
}
|
|
|
|
public static implicit operator Point((int X, int Y) point)
|
|
=> new(point.X, point.Y);
|
|
}
|
|
} |