105 lines
2.6 KiB
Python
105 lines
2.6 KiB
Python
|
#!/bin/python3
|
||
|
|
||
|
import sys
|
||
|
sys.setrecursionlimit(1500)
|
||
|
|
||
|
hmap = list()
|
||
|
|
||
|
with open('day12.txt', 'r') as f:
|
||
|
for line in f:
|
||
|
hmap.append(line.strip())
|
||
|
|
||
|
h = len(hmap)
|
||
|
w = len(hmap[0])
|
||
|
|
||
|
for y in range(h):
|
||
|
for x in range(w):
|
||
|
if hmap[y][x] == 'S':
|
||
|
start = (x, y)
|
||
|
if hmap[y][x] == 'E':
|
||
|
end = (x, y)
|
||
|
|
||
|
def get_elevation(char):
|
||
|
if char == 'S':
|
||
|
return ord('a')
|
||
|
if char == 'E':
|
||
|
return ord('z')
|
||
|
return ord(char)
|
||
|
|
||
|
def get_adjacents(pos):
|
||
|
(x, y) = pos
|
||
|
return [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]
|
||
|
|
||
|
def in_bounds(pos):
|
||
|
(x, y) = pos
|
||
|
return x >= 0 and x < w and y >= 0 and y < h
|
||
|
|
||
|
def get_char(hmap, pos):
|
||
|
(x, y) = pos
|
||
|
return hmap[y][x]
|
||
|
|
||
|
def valid_jump(hmap, pos, adj):
|
||
|
poschar = get_char(hmap, pos)
|
||
|
adjchar = get_char(hmap, adj)
|
||
|
poselev = get_elevation(poschar)
|
||
|
adjelev = get_elevation(adjchar)
|
||
|
return poselev + 1 >= adjelev
|
||
|
|
||
|
best_cost = {}
|
||
|
|
||
|
def find_path(hmap, path, pos):
|
||
|
if get_char(hmap, pos) == 'E':
|
||
|
return [path]
|
||
|
|
||
|
paths = list()
|
||
|
for adj in get_adjacents(pos):
|
||
|
if adj not in path and in_bounds(adj) and valid_jump(hmap, pos, adj):
|
||
|
if adj not in best_cost or best_cost[adj] > len(path):
|
||
|
best_cost[adj] = len(path)
|
||
|
new_path = set.copy(path)
|
||
|
new_path.add(adj)
|
||
|
paths.extend(find_path(hmap, new_path, adj))
|
||
|
return paths
|
||
|
|
||
|
shortest = None
|
||
|
|
||
|
paths = find_path(hmap, set([start]), start)
|
||
|
for path in paths:
|
||
|
if not shortest or len(path) < shortest:
|
||
|
shortest = len(path)
|
||
|
|
||
|
print('part1', shortest - 1)
|
||
|
|
||
|
trail_lengths = {}
|
||
|
|
||
|
def valid_jump2(hmap, pos, adj):
|
||
|
poschar = get_char(hmap, pos)
|
||
|
adjchar = get_char(hmap, adj)
|
||
|
poselev = get_elevation(poschar)
|
||
|
adjelev = get_elevation(adjchar)
|
||
|
return adjelev + 1 >= poselev
|
||
|
|
||
|
def find_trail(hmap, trail, pos):
|
||
|
for adj in get_adjacents(pos):
|
||
|
if adj not in trail and in_bounds(adj) and valid_jump2(hmap, pos, adj):
|
||
|
trail_length = len(trail) + 1
|
||
|
if adj not in trail_lengths or trail_lengths[adj] > trail_length:
|
||
|
trail_lengths[adj] = trail_length
|
||
|
new_trail = list.copy(trail)
|
||
|
new_trail.append(adj)
|
||
|
find_trail(hmap, new_trail, adj)
|
||
|
|
||
|
find_trail(hmap, [end], end)
|
||
|
|
||
|
shortest = None
|
||
|
|
||
|
for y in range(h):
|
||
|
for x in range(w):
|
||
|
if (x, y) in trail_lengths:
|
||
|
if get_elevation(get_char(hmap, (x, y))) == ord('a'):
|
||
|
trail_length = trail_lengths[(x, y)]
|
||
|
if not shortest or trail_length < shortest:
|
||
|
shortest = trail_length
|
||
|
|
||
|
print('part2', shortest - 1)
|