From ac95a204799cffce991ed365911a3b5fc190a9c6 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:05:20 -0600 Subject: [PATCH] feat: begin working on day 10 solution --- 10/HoofIt.Tests/TopoMapTests.cs | 44 +++++++++ 10/HoofIt/Program.cs | 153 +++++++++++++++++++++++++++++++- AdventOfCode2024.sln | 16 ++++ 3 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 10/HoofIt.Tests/TopoMapTests.cs diff --git a/10/HoofIt.Tests/TopoMapTests.cs b/10/HoofIt.Tests/TopoMapTests.cs new file mode 100644 index 0000000..15e8424 --- /dev/null +++ b/10/HoofIt.Tests/TopoMapTests.cs @@ -0,0 +1,44 @@ +namespace HoofIt.Tests; + +public class TopoMapTests +{ + private readonly string[] _exampleInput = [ + "89010123", + "78121874", + "87430965", + "96549874", + "45678903", + "32019012", + "01329801", + "10456732", + ]; + + [Test] + public async Task From_WhenCalled_ItShouldReturnNewInstanceOfTopoMap() + { + var result = TopoMap.From(_exampleInput); + + await Assert.That(result).IsTypeOf(); + } + + [Test] + public async Task GetTrailHeadScores_WhenCalledWithExampleInput_ItShouldReturnExpectedValues() + { + var expectedValues = new List() + { + 5, + 6, + 5, + 3, + 1, + 3, + 5, + 3, + 5, + }; + + var result = TopoMap.From(_exampleInput).GetTrailHeadScores(); + + await Assert.That(result).IsEqualTo(36); + } +} \ No newline at end of file diff --git a/10/HoofIt/Program.cs b/10/HoofIt/Program.cs index 3751555..4c7aa8d 100644 --- a/10/HoofIt/Program.cs +++ b/10/HoofIt/Program.cs @@ -1,2 +1,151 @@ -// See https://aka.ms/new-console-template for more information -Console.WriteLine("Hello, World!"); +using System.Diagnostics; + +if (args.Length is 0) +{ + Console.WriteLine("Please provide a path to the input file."); + return; +} + +if (File.Exists(args[0]) is false) +{ + Console.WriteLine("The provided file does not exist."); + return; +} + +var isPart2 = args.Length is 2 && args[1] is "part2"; +var input = await File.ReadAllLinesAsync(args[0]); + +var stopwatch = new Stopwatch(); +stopwatch.Start(); + +var map = TopoMap.From(input); + +// i'm going to to walk over the grid +// i'm going to only worry about places where +// there is a zero + +// need to check if we are on a nine +// before we explore...also we should +// be able to add to score here + +// when i encounter a zero i need to begin +// exploring nearby tiles that increment by 1 +// in each left, right, up, down direction +// any adj tile that fits this...is a tile i +// need to also explore + +stopwatch.Stop(); +Console.WriteLine($". ({stopwatch.ElapsedMilliseconds}ms)"); + +class TopoMap +{ + private static Direction[] _directions = [ + Direction.Up, + Direction.Down, + Direction.Left, + Direction.Right, + ]; + + private readonly string[] _grid; + + private TopoMap(string[] input) + { + _grid = input; + } + + public static TopoMap From(string[] input) => new(input); + + // TODO: This actually needs to be GetTrailHeadScore + // I want to perform this search when I know I've reached + // a trail head. + public int GetTrailHeadScores() + { + var trailheadScore = 0; + var visitedPositions = new HashSet(); + var positionsToVisit = new Queue(); + + var startingX = 0; + var startingY = 0; + var startingHeight = int.Parse(_grid[startingY][startingX].ToString()); + positionsToVisit.Enqueue(new(startingX, startingY, startingHeight)); + + while (positionsToVisit.Count != 0) + { + var currentPosition = positionsToVisit.Dequeue(); + + if (visitedPositions.Contains(currentPosition)) + { + continue; + } + + visitedPositions.Add(currentPosition); + + if (currentPosition.Height is 9) + { + trailheadScore++; + continue; + } + + foreach (var direction in _directions) + { + if (currentPosition.TryGetNextPosition(direction, _grid, out var newPosition) is false) + { + continue; + } + + if (visitedPositions.Contains(newPosition)) + { + continue; + } + + var heightDifference = newPosition.Height - currentPosition.Height; + + if (heightDifference is not 1) + { + continue; + } + + positionsToVisit.Enqueue(newPosition); + } + } + + return trailheadScore; + } +} + +record Position(int X, int Y, int Height) +{ + public bool TryGetNextPosition(Direction direction, string[] grid, out Position position) + { + var x = X + direction.XD; + var y = Y + direction.YD; + + position = new(x, y, -1); + + var isOffGrid = IsOffGrid(position, grid); + + if (isOffGrid) + { + return false; + } + + position = position with { Height = grid[y][x] }; + return true; + } + + private bool IsOffGrid(Position position, string[] grid) + { + return position.X < 0 || + position.X > grid[0].Length - 1 || + position.Y > grid.Length - 1 || + position.Y < 0; + } +} + +record Direction(int XD, int YD) +{ + public static Direction Up = new(0, -1); + public static Direction Down = new(0, 1); + public static Direction Left = new(-1, 0); + public static Direction Right = new(1, 0); +} \ No newline at end of file diff --git a/AdventOfCode2024.sln b/AdventOfCode2024.sln index ebeba76..f66902d 100644 --- a/AdventOfCode2024.sln +++ b/AdventOfCode2024.sln @@ -72,6 +72,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiskFragmenter", "09\DiskFr EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiskFragmenter.Tests", "09\DiskFragmenter.Tests\DiskFragmenter.Tests.csproj", "{9A7AAC2C-A23B-4FFE-8B2B-93E204904866}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "10", "10", "{7AB34145-87D1-4BB5-AF9C-E0239F8BE1DB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HoofIt", "10\HoofIt\HoofIt.csproj", "{5C4EC29A-3297-4D53-95EF-80800F3AF68A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HoofIt.Tests", "10\HoofIt.Tests\HoofIt.Tests.csproj", "{2FACCE14-0E91-4FAA-9105-711A2B4428C3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -153,6 +159,14 @@ Global {9A7AAC2C-A23B-4FFE-8B2B-93E204904866}.Debug|Any CPU.Build.0 = Debug|Any CPU {9A7AAC2C-A23B-4FFE-8B2B-93E204904866}.Release|Any CPU.ActiveCfg = Release|Any CPU {9A7AAC2C-A23B-4FFE-8B2B-93E204904866}.Release|Any CPU.Build.0 = Release|Any CPU + {5C4EC29A-3297-4D53-95EF-80800F3AF68A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5C4EC29A-3297-4D53-95EF-80800F3AF68A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5C4EC29A-3297-4D53-95EF-80800F3AF68A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5C4EC29A-3297-4D53-95EF-80800F3AF68A}.Release|Any CPU.Build.0 = Release|Any CPU + {2FACCE14-0E91-4FAA-9105-711A2B4428C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2FACCE14-0E91-4FAA-9105-711A2B4428C3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2FACCE14-0E91-4FAA-9105-711A2B4428C3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2FACCE14-0E91-4FAA-9105-711A2B4428C3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {1AFE2FF1-A55D-4D86-A9BB-9875CA0D14D8} = {270B7829-6D23-4B34-91FE-D87D533AF2AB} @@ -173,5 +187,7 @@ Global {4741807B-CD85-4A87-BE6E-DC506C4CD1E6} = {F2A51E88-BCCC-4778-9369-63E72D052554} {EDD2A424-2BD0-408F-A32D-E5AE3316B68E} = {2971DA3F-AD59-4BE1-A860-4F1B60BCB771} {9A7AAC2C-A23B-4FFE-8B2B-93E204904866} = {2971DA3F-AD59-4BE1-A860-4F1B60BCB771} + {5C4EC29A-3297-4D53-95EF-80800F3AF68A} = {7AB34145-87D1-4BB5-AF9C-E0239F8BE1DB} + {2FACCE14-0E91-4FAA-9105-711A2B4428C3} = {7AB34145-87D1-4BB5-AF9C-E0239F8BE1DB} EndGlobalSection EndGlobal