Files
AdventOfCode/Days/Day10.cs
2025-01-24 10:19:12 +01:00

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);
}
}