141 lines
4.6 KiB
Python
141 lines
4.6 KiB
Python
# --- Day 12: Hill Climbing Algorithm ---
|
|
|
|
# You try contacting the Elves using your handheld device, but the river you're
|
|
# following must be too low to get a decent signal.
|
|
|
|
# You ask the device for a heightmap of the surrounding area (your puzzle
|
|
# input). The heightmap shows the local area from above broken into a grid;
|
|
# the elevation of each square of the grid is given by a single lowercase
|
|
# letter, where a is the lowest elevation, b is the next-lowest, and so on up
|
|
# to the highest elevation, z.
|
|
|
|
# Also included on the heightmap are marks for your current position (S) and
|
|
# the location that should get the best signal (E). Your current position (S)
|
|
# has elevation a, and the location that should get the best signal (E) has
|
|
# elevation z.
|
|
|
|
# You'd like to reach E, but to save energy, you should do it in as few steps
|
|
# as possible. During each step, you can move exactly one square up, down,
|
|
# left, or right. To avoid needing to get out your climbing gear, the elevation
|
|
# of the destination square can be at most one higher than the elevation of
|
|
# your current square; that is, if your current elevation is m, you could step
|
|
# to elevation n, but not to elevation o. (This also means that the elevation
|
|
# of the destination square can be much lower than the elevation of your
|
|
# current square.)
|
|
|
|
# For example:
|
|
|
|
# Sabqponm
|
|
# abcryxxl
|
|
# accszExk
|
|
# acctuvwj
|
|
# abdefghi
|
|
|
|
# Here, you start in the top-left corner; your goal is near the middle. You
|
|
# could start by moving down or right, but eventually you'll need to head
|
|
# toward the e at the bottom. From there, you can spiral around to the goal:
|
|
|
|
# v..v<<<<
|
|
# >v.vv<<^
|
|
# .>vv>E^^
|
|
# ..v>>>^^
|
|
# ..>>>>>^
|
|
|
|
# In the above diagram, the symbols indicate whether the path exits each
|
|
# square moving up (^), down (v), left (<), or right (>). The location that
|
|
# should get the best signal is still E, and . marks unvisited squares.
|
|
|
|
# This path reaches the goal in 31 steps, the fewest possible.
|
|
|
|
# What is the fewest steps required to move from your current position to the
|
|
# location that should get the best signal?
|
|
|
|
with open("/home/xfeluser/AoC_2022/P12.txt") as f:
|
|
diagram = {
|
|
(x, y): ord(e)
|
|
for y, line in enumerate(f.read().strip().split("\n"))
|
|
for x, e in enumerate(line.strip())
|
|
}
|
|
|
|
start = [k for k in diagram if diagram[k] == ord("S")][0]
|
|
end = [k for k in diagram if diagram[k] == ord("E")][0]
|
|
# Use expected value for starting/ending point
|
|
diagram[start] = ord("a")
|
|
diagram[end] = ord("z")
|
|
|
|
queue = [(start, 0)]
|
|
pos_to_steps = {}
|
|
|
|
while queue:
|
|
cur, steps = queue.pop()
|
|
|
|
if cur not in pos_to_steps or steps < pos_to_steps[cur]:
|
|
pos_to_steps[cur] = steps
|
|
|
|
for offset in ((1, 0), (-1, 0), (0, 1), (0, -1)):
|
|
new_pos = cur[0] + offset[0], cur[1] + offset[1]
|
|
|
|
if new_pos in diagram and diagram[new_pos] - diagram[cur] <= 1:
|
|
queue.append((new_pos, steps + 1))
|
|
|
|
print(pos_to_steps[end])
|
|
|
|
|
|
# --- Part Two ---
|
|
|
|
# As you walk up the hill, you suspect that the Elves will want to turn this
|
|
# into a hiking trail. The beginning isn't very scenic, though; perhaps you can
|
|
# find a better starting point.
|
|
|
|
# To maximize exercise while hiking, the trail should start as low as possible:
|
|
# elevation a. The goal is still the square marked E. However, the trail should
|
|
# still be direct, taking the fewest steps to reach its goal. So, you'll need
|
|
# to find the shortest path from any square at elevation a to the square marked
|
|
# E.
|
|
|
|
# Again consider the example from above:
|
|
|
|
# Sabqponm
|
|
# abcryxxl
|
|
# accszExk
|
|
# acctuvwj
|
|
# abdefghi
|
|
|
|
# Now, there are six choices for starting position (five marked a, plus the
|
|
# square marked S that counts as being at elevation a). If you start at the
|
|
# bottom-left square, you can reach the goal most quickly:
|
|
|
|
# ...v<<<<
|
|
# ...vv<<^
|
|
# ...v>E^^
|
|
# .>v>>>^^
|
|
# >^>>>>>^
|
|
|
|
# This path reaches the goal in only 29 steps, the fewest possible.
|
|
|
|
# What is the fewest steps required to move starting from any square with
|
|
# elevation a to the location that should get the best signal?
|
|
|
|
starts = []
|
|
pos_to_steps = {}
|
|
|
|
for start in [k for k in diagram if diagram[k] == ord("a")]:
|
|
queue = [(start, 0)]
|
|
|
|
while queue:
|
|
cur, steps = queue.pop()
|
|
|
|
if cur not in pos_to_steps or steps < pos_to_steps[cur]:
|
|
pos_to_steps[cur] = steps
|
|
|
|
for offset in ((1, 0), (-1, 0), (0, 1), (0, -1)):
|
|
new_pos = cur[0] + offset[0], cur[1] + offset[1]
|
|
|
|
if new_pos in diagram and diagram[new_pos] - diagram[cur] <= 1:
|
|
queue.append((new_pos, steps + 1))
|
|
|
|
if end in pos_to_steps:
|
|
starts.append(pos_to_steps[end])
|
|
|
|
print(min(starts))
|