# --- 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))