Anyway, this is going well, I'm having fun with the puzzles and chatting with colleagues in the AoC Slack channel.
Plain sailing, blue skies... wasn't struggling with any of the puzzles. May have been neglecting some downtime from the computer though, but hey, if it's fun, it's fun right?
Really enjoying the puzzles from both years (but still itching to finish them, so I could fill in the missing 2020 gap.)
Then 2021.15 dropped.
I am writing this a couple of months after the fact, so my memory isn't razor sharp, but I really struggled with this one even though I thought I knew what I needed to do.
This is where I had to start using visualisations that would become more sophisticated as I progressed through the puzzles.
I started with these visualisations to help me reason about the problem:
But as you can see, especially from the second one, my approach was not going to finish any time soon.Also, as I had set myself a performance target, I really didn't want the visualisations to impact the puzzle when not required. This ended up with a lot of conditional compilation, which I wasn't over the moon about.
protected int Solve() { var queue = new PriorityQueue<Node, int>(); queue.Enqueue(_rootNode, int.MaxValue); var costs = new Dictionary<int, int> { { 0, 0 } }; #if DUMP && DEBUG Console.Clear(); Console.CursorVisible = false; Console.ForegroundColor = ConsoleColor.DarkGray; #endif while (queue.Count > 0) { var node = queue.Dequeue(); #if DUMP && DEBUG Console.CursorLeft = node.Position.X; Console.CursorTop = node.Position.Y; Console.Write('█'); #endif if (node.Position.X == _width - 1 && node.Position.Y == _height - 1) { break; } foreach (var neighbor in node.Neighbors) { var cost = costs[node.Position.X + node.Position.Y * _width] + neighbor.Value; if (! costs.TryGetValue(neighbor.Position.X + neighbor.Position.Y * _width, out var nextCost) || cost < nextCost) { costs[neighbor.Position.X + neighbor.Position.Y * _width] = cost; queue.Enqueue(neighbor, cost); } } #if DUMP && DEBUG DrawPath(costs); #endif } }
I would solve the conditional compilation issue later on. For now I was focused on getting the puzzles completed.
After a lot of wrong turns, a geeky friend of mine told me to look up Dijkstra's Algorithm which I duly implemented (code above.)
This was a bit of a revelation and worked a treat as you can see from this visualisation. Without outputting to the console, the puzzle executes in about 4ms.
