From 6053c261433c99d24f13712b0e20006faa027df4 Mon Sep 17 00:00:00 2001 From: smabuk <2011834+smabuk@users.noreply.github.com> Date: Mon, 16 Dec 2024 22:23:42 +0000 Subject: [PATCH] 2024 Day16 Part2 WIP still passing tests --- Solutions/2024/Day16.cs | 70 +++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/Solutions/2024/Day16.cs b/Solutions/2024/Day16.cs index 39af4d2..688b04a 100644 --- a/Solutions/2024/Day16.cs +++ b/Solutions/2024/Day16.cs @@ -11,6 +11,7 @@ public static partial class Day16 { private const char START = 'S'; private const char END = 'E'; private const char WALL = '#'; + private const int TURN_COST = 1000; private static char[,] _maze = default!; private static Action? _visualise = null; @@ -29,9 +30,9 @@ public static int Part1(string[] _) ReindeerPosition reindeerPosition = new(_maze.ForEachCell().Single(c => c.Value is START).Index, East); Point end = _maze.ForEachCell().Single(c => c.Value is END).Index; - (int lowestScore, List route) = _maze.FindShortestPath(reindeerPosition, end); + (int lowestScore, List route) = _maze.FindShortestPath(reindeerPosition, end); - _maze.VisualiseMaze($"Lowest Score {lowestScore}:", route); + _maze.VisualiseMaze($"Lowest Score {lowestScore}:", route[1..^1]); return lowestScore; } @@ -41,59 +42,59 @@ public static int Part2(string[] _) ReindeerPosition reindeerPosition = new(_maze.ForEachCell().Single(c => c.Value is START).Index, East); Point end = _maze.ForEachCell().Single(c => c.Value is END).Index; - List<(int Score, List Route)> routes = [.. _maze.FindAllPaths(reindeerPosition, end)]; + List<(int Score, List Route)> routes = [.. _maze.FindAllPaths(reindeerPosition, end)]; int lowestScore = routes.Min(route => route.Score); - List tiles = [..routes.Where(r => r.Score == lowestScore).SelectMany(p => p.Route).Distinct()]; - _maze.VisualiseMaze($"Tiles:", tiles); + List tiles = [..routes.Where(r => r.Score == lowestScore).SelectMany(p => p.Route)]; + _maze.VisualiseMaze($"Tiles:", tiles.Select(r => r with { Direction = None })); - return tiles.Count; + return tiles.Select(p => p.Position).Distinct().Count(); } - private static IEnumerable<(int, List)> FindAllPaths(this char[,] maze, ReindeerPosition start, Point end) + private static IEnumerable<(int, List)> FindAllPaths(this char[,] maze, ReindeerPosition start, Point end) { - Queue<(int, List, Direction)> queue = new(); - queue.Enqueue((0, new List { start.Position }, start.Direction)); - HashSet visited = []; + Queue<(int, List, Direction)> queue = new(); + queue.Enqueue((0, new List { start }, start.Direction)); + HashSet visited = []; while (queue.Count > 0) { - (int currentDist, List path, Direction prevDir) = queue.Dequeue(); - Point position = path[^1]; + (int currentDist, List path, Direction prevDir) = queue.Dequeue(); + ReindeerPosition reindeerPosition = path[^1]; - if (position == end) { + if (reindeerPosition.Position == end) { yield return (currentDist, [.. path]); continue; } - _ = visited.Add(position); + _ = visited.Add(reindeerPosition); foreach (Direction direction in Directions.NESW) { - Point newPosition = position + direction.Delta(); + ReindeerPosition newPosition = reindeerPosition with { Position = reindeerPosition.Position + direction.Delta(), Direction = direction}; - if (maze.TryGetValue(newPosition, out char value) && value is not WALL - && !path.Contains(newPosition) - //&& !visited.Contains(newPosition) + if (maze[newPosition.Position.X, newPosition.Position.Y] is not WALL + //&& path.DoesNotContain(newPosition) + && visited.DoesNotContain(newPosition) ) { - int turnCost = prevDir != direction ? 1000 : 0; + int turnCost = (prevDir != direction) ? TURN_COST : 0; int newDist = currentDist + 1 + turnCost; - List newPath = [.. path, newPosition]; + List newPath = [.. path, newPosition]; queue.Enqueue((newDist, newPath, direction)); } } } } - private static (int, List) FindShortestPath(this char[,] maze, ReindeerPosition start, Point end) + private static (int, List) FindShortestPath(this char[,] maze, ReindeerPosition start, Point end) { int noOfRows = maze.RowsCount(); int noOfCols = maze.ColsCount(); int[,] distances = new int[noOfCols, noOfRows]; - Point[,] previous = new Point[noOfCols, noOfRows]; + ReindeerPosition[,] previous = new ReindeerPosition[noOfCols, noOfRows]; distances.FillInPlace(int.MaxValue); - previous.FillInPlace(new Point(-1, -1)); + previous.FillInPlace(new ReindeerPosition(new Point(-1, -1), None)); distances[start.Position.X, start.Position.Y] = 0; PriorityQueue<(int, Point, Direction), int> pq = new(); @@ -103,8 +104,8 @@ private static (int, List) FindShortestPath(this char[,] maze, ReindeerPo (int currentDist, Point position, Direction prevDir) = pq.Dequeue(); if (position ==end) { - List path = []; - for (Point at = end; at.X != -1 && at.Y != -1; at = previous[at.X, at.Y]) { + List path = []; + for (ReindeerPosition at = new(end, None); at.Position.X != -1 && at.Position.Y != -1; at = previous[at.Position.X, at.Position.Y]) { path.Add(at); } @@ -116,11 +117,11 @@ private static (int, List) FindShortestPath(this char[,] maze, ReindeerPo Point newPosition = position + direction.Delta(); if (maze.TryGetValue(newPosition, out char value) && value is not WALL) { - int turnCost = (prevDir != direction) ? 1000 : 0; + int turnCost = (prevDir != direction) ? TURN_COST : 0; int newDist = currentDist + 1 + turnCost; if (newDist < distances[newPosition.X, newPosition.Y]) { distances[newPosition.X, newPosition.Y] = newDist; - previous[newPosition.X, newPosition.Y] = position; + previous[newPosition.X, newPosition.Y] = new (position, direction); pq.Enqueue((newDist, newPosition, direction), newDist); } } @@ -137,7 +138,7 @@ private record Step(ReindeerPosition Position, Direction PreviousDirection) public int Score => Position.Direction != PreviousDirection ? 1001 : 1; } - private static void VisualiseMaze(this char[,] map, string title, IEnumerable? route = null, bool clearScreen = false) + private static void VisualiseMaze(this char[,] map, string title, IEnumerable? route = null, bool clearScreen = false) { if (_visualise is null) { return; @@ -145,11 +146,18 @@ private static void VisualiseMaze(this char[,] map, string title, IEnumerable '^', + East => '>', + West => '<', + South => 'v', + _ => 'O', + }; } - string[] output = ["", title, .. outputMap.AsStrings()]; + string[] output = ["", title, .. outputMap.AsStrings().Select(s => s.Replace('.', ' '))]; _visualise?.Invoke(output, clearScreen); } }