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(); 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 TrailHeads) ParseMap() { var heightMap = new byte[MapSize, MapSize]; var trailHeads = new List(); 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, ISubtractionOperators, IMultiplyOperators { 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); } }