Metadata
-
Date
-
Tagged
-
Part of series
- Advent of Code 2022 Day 1
- Advent of Code 2022 Day 2
- Advent of Code 2022 Day 3
- Advent of Code 2022 Day 4
- Advent of Code 2022 Day 5
- Advent of Code 2022 Day 6
- Advent of Code 2022 Day 7
- Advent of Code 2022 Day 8
- Advent of Code 2022 Day 9
- Advent of Code 2022 Day 10
- Advent of Code 2022 Day 11
- Advent of Code 2022 Day 12
- Advent of Code 2022 Day 13
- Advent of Code 2022 Day 14
- Advent of Code 2022 Day 15
- Advent of Code 2022 Day 16
- Advent of Code 2022 Day 17
- Advent of Code 2022 Day 18
- Advent of Code 2022 Day 19
- Advent of Code 2022 Day 20
- Advent of Code 2022 Day 21
- Advent of Code 2022 Day 22
- Advent of Code 2022 Day 23
- Advent of Code 2022 Day 24
- Advent of Code 2022 Day 25
-
Older post
-
Newer post
Advent of Code 2022 Day 12
Day 12: Hill Climbing Algorithm
https://adventofcode.com/2022/day/12
You want to get to a higher spot so your communication device gets better reception.
Today’s input is a height map of the surrounding area. Again, it’s a perfect 2D grid of positions.
Each position has an elevation from “a” to “z”. “a” being the lowest and “z” the highest.
You start at the position marked “S”. It has an elevation of “a”.
You want to go to the position marked “E”. It has an elevation of “z”.
An example input looks like this:
During each step, you can move exactly one square up, down, left, or right.
You can only go up one height per step. So from “a” to “b” is possible. But going from “a” to “c” is not.
You can go down as many heights as you want. (I guess you are wearing long fall boots from Portal. So going from “y” to “a” is a perfectly valid move.
Parsing
I decided to extract a couple things from the input:
- The height map, with numbers from 0-25 instead of letters.
- The coordinates for the start (marked “S”)
- The coordinates for the end (marked “E”)
- The width of the map
- The height of the map
I used a list of lists to store every height.
- Each item in the outer list is a row.
- Each item in a row is a height.
I used a Coord
struct again to store coordinates.
I use the good ‘ol double for loop to loop over each letter in the map.
When I encounter an “S”.
- I set its height to “a”.
- I set the
start
coordinate.
When I encounter an “E”.
- I set its height to “z”.
- I set the
end
coordinate.
I turn the height letter into a height number by using the ASCII values again. (as in multiple previous days) That number gets stored in the height map at the corrent row and column index.
Part 1
The question asks for the fewest steps required to “E” if starting from “S”.
Aha, a shortest path problem! Time to bring out our good friend Dijkstra.
- The start position is
start
. - The goal position is
end
. - Per step, the cost increases by 1.
It never makes sense to visit a location twice, you could have stepped in the correct direction the first time. That’s why I also keep track of coordinates the algoritm visited in a set, and only examine new coordinates.
in pseudocode:
Helpers
To make it a bit more readable I’ll define a few helpers again. To get all neighbours of a current position given the width and the height of the map:
This doesn’t care about the height at a coordinate, only that a coordinate exists on our map!
I also created a Node
struct that will be the thing we insert into our priority queue.
It has a cost, and a coordinate.
The priority queue has to be ordered so the thing with the lowest cost gets popped first, so I implement Ord
to get that behaviour.
Because this comes with a few other requirements (being able to compare Node
, and because I plan on inserting a node into a set, I derive some traits on Coord
and Node
.
They’re both small, so I derive Copy
while I’m at it.
Before looping over candidates in the algorithm, I calculate all neighbours. Then, I filter those and only keep the ones that satisfy the rules.
Filling in the skeleton code gives the answer to part1.
A node at position end
eventually gets popped off the priority queue.
At that point, we can be certain this node has the lowest cost to reach that coordinate.
Final code
Part 2
The question asks for the fewest steps required to reach “E” if starting from any “a”.
To do this, I flipped the logic from part 1, and adjusted the rules.
The parameters for the Dijkstra algorithm are now:
- The start position is
end
. - The goal position is any
a
. - Per step, the cost increases by 1.
The rules from the initial problem also invert!
- You can only go down one height per step.
- You can go up as many heights as you want.
Translated into code, our return
condition changes, and the spot we filter
neighbours to apply the rules changes.
Making those changes, and boom, that’s part2!