Day 12 - Advent of Code 2022
Working solutions for the day 12 puzzles.
Part One
""" day_12_01.py """
# usage: python3 day_12_01.py < input
import sys
def parse(data):
""" create dictionary of paths """
def neighbours(point):
""" calculate valid neighbours """
def diff(p1, p2):
""" difference in heights """
mapping = {'S': 'a', 'E': 'z'}
x1, y1, x2, y2 = *p1, *p2
v1 = mapping.get(heights[y1][x1], heights[y1][x1])
v2 = mapping.get(heights[y2][x2], heights[y2][x2])
return ord(v1) - ord(v2)
deltas = [(-1, 0), (1, 0), (0, -1), (0, 1)]
xp, yp = point
options = [(xp + dx, yp + dy) for dx, dy in deltas]
x_max, y_max = len(heights[0]), len(heights)
valid = [(x, y) for x, y in options
if x in range(x_max) and y in range(y_max)]
return [(x, y) for x, y in valid if diff((x, y), (xp, yp)) <= 1]
heights = [list(row) for row in data.splitlines()]
output = {}
for y, row in enumerate(heights):
for x, value in enumerate(row):
if value == 'S':
output['start'] = (x, y)
elif value == 'E':
output['end'] = (x, y)
output[(x, y)] = neighbours((x, y))
return output
def shortest_path(start, end, data):
""" calculate shortest path from start to end """
track = {start: [start]}
queue = [start]
while queue:
latest = queue.pop(0)
for step in data[latest]:
if step not in track:
track[step] = [track[latest], step]
queue.append(step)
output = []
while track[end]:
output.append(track[end].pop())
if track[end]:
track[end] = track[end][0]
output.reverse()
return output
paths = parse(sys.stdin.read())
print(len(shortest_path(paths['start'], paths['end'], paths)) - 1)
Part Two
""" day_12_02.py """
# usage: python3 day_12_02.py < input
import sys
def parse(data):
""" create dictionary of paths """
def neighbours(point):
""" calculate valid neighbours """
def diff(p1, p2):
""" difference in heights """
mapping = {'S': 'a', 'E': 'z'}
x1, y1, x2, y2 = *p1, *p2
v1 = mapping.get(heights[y1][x1], heights[y1][x1])
v2 = mapping.get(heights[y2][x2], heights[y2][x2])
return ord(v1) - ord(v2)
deltas = [(-1, 0), (1, 0), (0, -1), (0, 1)]
xp, yp = point
options = [(xp + dx, yp + dy) for dx, dy in deltas]
x_max, y_max = len(heights[0]), len(heights)
valid = [(x, y) for x, y in options
if x in range(x_max) and y in range(y_max)]
return [(x, y) for x, y in valid if diff((x, y), (xp, yp)) <= 1]
heights = [list(row) for row in data.splitlines()]
output = {}
for y, row in enumerate(heights):
for x, value in enumerate(row):
if value == 'S':
output['start'] = (x, y)
elif value == 'E':
output['end'] = (x, y)
if value in ['a', 'S']:
output['a'] = output.get('a', []) + [(x, y)]
output[(x, y)] = neighbours((x, y))
return output
def shortest_path(start, end, data):
""" calculate shortest path from start to end """
track = {start: [start]}
queue = [start]
while queue:
latest = queue.pop(0)
for step in data[latest]:
if step not in track:
track[step] = [track[latest], step]
queue.append(step)
output = []
while track.get(end):
output.append(track[end].pop())
if track[end]:
track[end] = track[end][0]
output.reverse()
return output
paths = parse(sys.stdin.read())
candidates = [len(shortest_path(start, paths['end'], paths))
for start in paths['a']]
print(min([i for i in candidates if i > 0]) - 1)