Day 20: Race Condition
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465
16 Comments
cabhan@discuss.tchncs.de · 3 pts · 1y
Rust
I was stuck for a while, even after getting a few hints, until I read the problem more closely and realized: there is only one non-cheating path, and every free space is on it. This means that the target of any shortcut is guaranteed to be on the shortest path to the end.
This made things relatively simple. I used Dijkstra to calculate the distance from the start to each space. I then looked at every pair of points: if they are a valid distance away from each other, check how much time I would save jumping from one to the next. If that amount of time is in the range we want, then this is a valid cheat.
https://gitlab.com/bricka/advent-of-code-2024-rust/-/blob/main/src/days/day20.rs?ref_type=heads
::: spoiler The Code
:::
lwhjp@lemmy.sdf.org · 3 pts · 1y
Haskell
I should probably do something about the n^2^ loop inSomewhat better (0.575s). Can't shake the feeling that I'm missing an obvious closed-form solution, though.findCheats, but it's fast enough for now. Besides, my brain has melted.lwhjp@lemmy.sdf.org · 1 pts · 1y
Ah, the number of potential start points is much smaller than the length of the path. I guess a map from position to offset would do it, but I'm not sure it's really worth it.
LeixB@lemmy.world · 2 pts · 1y
Haskell
::: spoiler solution
:::
lwhjp@lemmy.sdf.org · 1 pts · 1y
Beautiful!
sjmulder@lemmy.sdf.org · 2 pts · 1y
C
Note to self: reread the puzzle after waking up properly! I initially wrote a great solution for the wrong question (pathfinding with a given number of allowed jumps).
For the actual question, a bit boring but flood fill plus some array iteration saved the day again. Find the cost for every open tile with flood fill, then for each position and offset combination, see if that jump yields a lower cost at the destination.
For arbitrary inputs this would require eliminating the non-optimal paths, but the one path covered all open tiles.
::: spoiler Code
:::
https://codeberg.org/sjmulder/aoc/src/branch/master/2024/c/day20.c
Gobbel2000@programming.dev · 2 pts · 1y
Rust
The important part here is to build two maps first that hold for every point on the path the distance to the start and the distance to the end respectively. Then calculating the path length for a cheat vector is a simple lookup. For part 2 I first generated all vectors with manhattan distance <= 20, or more specifically, exactly half of those vectors to avoid checking the same vector in both directions.
Part 2 takes 15ms. The code looks a bit unwieldy at parts and uses the pyramid of doom paradigm but works pretty well.
::: spoiler Solution
:::
Also on github
VegOwOtenks@lemmy.world · 2 pts · 1y
Haskell
First parse and floodfill from start, each position then holds the distance from the start
For part 1, I check all neighbor tiles of neighbor tiles that are walls and calculate the distance that would've been in-between.
In part 2 I check all tiles within a manhattan distance
<= 20and calculate the distance in-between on the path. Then filter out all cheats<100and countTakes 1.4s sadly, I believe there is still potential for optimization.
Edit: coding style
gedhrel@lemmy.world · 3 pts · 1y
Hey - I've a question about this. Why is it correct? (Or is it?)
If you have two maps for positions in the maze that give (distance to end) and (distance from start), then you can select for points p1, p2 such that
d(p1, p2) + distance-to-end(p1) + distance-to-start(p2) <= best - 100
however, your version seems to assume that distance-to-end(p) = best - distance-to-start(p) - surely this isn't always the case?
Gobbel2000@programming.dev · 4 pts · 1y
There is exactly one path without cheating, so yes, the distance to one end is always the total distance minus the distance to the other end.
gedhrel@lemmy.world · 2 pts · 1y
Gotcha, thanks. I just re-read the problem statement and looked at the input and my input has the strongest possible version of that constraint: the path is unbranching and has start and end at the extremes. Thank-you!
Deebster@programming.dev · 2 pts · 1y
I missed that line too:
So I also did my pathfinding for every variation in the first part, but realised something must be wrong with my approach when I saw part 2.
gedhrel@lemmy.world · 3 pts · 1y
(I ask because everyone's solution seems to make the same assumption - that is, that you're finding a shortcut onto the same path, as opposed to onto a different path.)
VegOwOtenks@lemmy.world · 1 pts · 1y
Some others have answered already, but yes, there was a well-hidden line in the problem description about the map having only a single path from start to end..
mykl@lemmy.world · 2 pts · 1y
Dart
Simple path-finding + brute force. O(n*sqrt-n) I think but only takes ~200 milliseconds so that'll do for today. Time to walk the dog!
After being so pleased to have written my own path-finding algorithm the other day, I discovered that my regular
morelibrary already includes one. D'oh.(edit: shaved some milliseconds off)
addie@feddit.uk · 2 pts · 1y
C++ / Boost
Ah, cunning - my favourite one so far this year, I think. Nothing too special compared to the other solutions - floods the map using Dijkstra, then checks "every pair" for how much of a time saver it is. 0.3s on my laptop; it iterates through every pair twice since it does part 1 and part 2 separately, which could easily be improved upon.
::: spoiler spoiler
:::