Skip to content

Commit

Permalink
2024 Day16 Part2 WIP passing tests
Browse files Browse the repository at this point in the history
  • Loading branch information
smabuk committed Dec 16, 2024
1 parent a0ab89f commit f17f9d4
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 10 deletions.
65 changes: 55 additions & 10 deletions Solutions/2024/Day16.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static void LoadMaze(string[] input, Action<string[], bool>? visualise =
_maze.VisualiseMaze("Initial state:");
}

public static int Part1(string[] _, params object[]? args)
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;
Expand All @@ -36,7 +36,54 @@ public static int Part1(string[] _, params object[]? args)
return lowestScore;
}

public static string Part2(string[] input, params object[]? args) => NO_SOLUTION_WRITTEN_MESSAGE;
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<Point> Route)> routes = [.. _maze.FindAllPaths(reindeerPosition, end)];
int lowestScore = routes.Min(route => route.Score);

List<Point> tiles = [..routes.Where(r => r.Score == lowestScore).SelectMany(p => p.Route).Distinct()];
_maze.VisualiseMaze($"Tiles:", tiles);

return tiles.Count;
}

private static IEnumerable<(int, List<Point>)> FindAllPaths(this char[,] maze, ReindeerPosition start, Point end)
{
Queue<(int, List<Point>, Direction)> queue = new();
queue.Enqueue((0, new List<Point> { start.Position }, start.Direction));
HashSet<Point> visited = [];

while (queue.Count > 0) {
(int currentDist, List<Point> path, Direction prevDir) = queue.Dequeue();
Point position = path[^1];


if (position == end) {
yield return (currentDist, [.. path]);
continue;
}

_ = visited.Add(position);

foreach (Direction direction in Directions.NESW) {
Point newPosition = position + direction.Delta();

if (maze.TryGetValue(newPosition, out char value) && value is not WALL
&& !path.Contains(newPosition)
//&& !visited.Contains(newPosition)
)
{
int turnCost = prevDir != direction ? 1000 : 0;
int newDist = currentDist + 1 + turnCost;
List<Point> newPath = [.. path, newPosition];
queue.Enqueue((newDist, newPath, direction));
}
}
}
}

private static (int, List<Point>) FindShortestPath(this char[,] maze, ReindeerPosition start, Point end)
{
Expand All @@ -49,14 +96,13 @@ private static (int, List<Point>) FindShortestPath(this char[,] maze, ReindeerPo
previous.FillInPlace(new Point(-1, -1));

distances[start.Position.X, start.Position.Y] = 0;
SortedSet<(int, Point, Direction)> pq = [];
_ = pq.Add((0, start.Position, start.Direction));
PriorityQueue<(int, Point, Direction), int> pq = new();
pq.Enqueue((0, start.Position, start.Direction), 0);

while (pq.Count > 0) {
(int currentDist, Point position, Direction prevDir) = pq.Min;
_ = pq.Remove(pq.Min);
(int currentDist, Point position, Direction prevDir) = pq.Dequeue();

if (position.Equals(end)) {
if (position ==end) {
List<Point> path = [];
for (Point at = end; at.X != -1 && at.Y != -1; at = previous[at.X, at.Y]) {
path.Add(at);
Expand All @@ -73,10 +119,9 @@ private static (int, List<Point>) FindShortestPath(this char[,] maze, ReindeerPo
int turnCost = (prevDir != direction) ? 1000 : 0;
int newDist = currentDist + 1 + turnCost;
if (newDist < distances[newPosition.X, newPosition.Y]) {
_ = pq.Remove((distances[newPosition.X, newPosition.Y], newPosition, direction));
distances[newPosition.X, newPosition.Y] = newDist;
previous[newPosition.X, newPosition.Y] = position;
_ = pq.Add((newDist, newPosition, direction));
pq.Enqueue((newDist, newPosition, direction), newDist);
}
}
}
Expand All @@ -101,7 +146,7 @@ private static void VisualiseMaze(this char[,] map, string title, IEnumerable<Po
char[,] outputMap = (char[,])map.Clone();

foreach (Point point in route ?? []) {
outputMap[point.X, point.Y] = 'x';
outputMap[point.X, point.Y] = 'O';
}

string[] output = ["", title, .. outputMap.AsStrings()];
Expand Down
45 changes: 45 additions & 0 deletions Tests/2024/Tests_16.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,51 @@ public async Task Part1(string input, int expected)
}


[Theory]
[InlineData("""
###############
#.......#....E#
#.#.###.#.###.#
#.....#.#...#.#
#.###.#####.#.#
#.#.#.......#.#
#.#.#####.###.#
#...........#.#
###.#.#####.#.#
#...#.....#.#.#
#.#.#.###.#.#.#
#.....#...#.#.#
#.###.#.#.#.#.#
#S..#.....#...#
###############
""", 45)]
[InlineData("""
#################
#...#...#...#..E#
#.#.#.#.#.#.#.#.#
#.#.#.#...#...#.#
#.#.#.#.###.#.#.#
#...#.#.#.....#.#
#.#.#.#.#.#####.#
#.#...#.#.#.....#
#.#.#####.#.###.#
#.#.#.......#...#
#.#.###.#####.###
#.#.#...#.....#.#
#.#.#.#####.###.#
#.#.#.........#.#
#.#.#.#########.#
#S#.............#
#################
""", 64)]
public async Task Part2(string input, int expected)
{
_ = int.TryParse(SolutionRouter.SolveProblem(YEAR, DAY, PART2, input, new Action<string[], bool>(Callback)), out int actual);
actual.ShouldBe(expected);
await Task.Delay(200); // Allow time to visualise
}



private void Callback(string[] lines, bool _)
{
Expand Down

0 comments on commit f17f9d4

Please sign in to comment.