|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- import collections
- import itertools
- import sys
- from functools import partial
-
- from toolkit import read_image, render, shortest_path
-
-
- def read_in(text):
- grid = read_image(text)
- elements = {v: k for k, v in grid.items()}
- keys = {c for c in elements if c.isalpha() and c.islower()}
- return dict(grid), elements, keys
-
-
- def move(grid, pos):
- for ori in [1, -1, 1j, -1j]:
- if grid[pos + ori] != '#':
- yield pos + ori
-
-
- def trim(states, metric):
- groups = collections.defaultdict(list)
- for state in states:
- tips = frozenset(seq[-1] for seq in state)
- bulk = frozenset(' '.join(state))
- groups[bulk, tips].append(state)
- return [min(groups[k], key=metric) for k in groups]
-
-
- def precalc_moves(entrances, keys, elements, grid):
- requirements = collections.defaultdict(dict)
- lengths = {}
- for a, b in itertools.combinations(keys.union(entrances), 2):
- try:
- path = shortest_path(elements[a], elements[b], partial(move, grid))
- *glyphs, = map(grid.get, path)
- except RuntimeError:
- continue
- lengths[a, b] = len(path) - 1
- lengths[b, a] = len(path) - 1
- requirements[a][b] = {c.lower() for c in glyphs if c.isupper()}
- requirements[b][a] = {c.lower() for c in glyphs if c.isupper()}
- return requirements, partial(calc_total, lengths)
-
-
- def calc_total(lengths, state):
- return sum(lengths[pair] for seq in state for pair in zip(seq, seq[1:]))
-
-
- def mod_grid(text):
- grid, elements, keys = read_in(text)
- pos = elements['@']
- grid[pos] = '#'
- for char, ori in zip('*&^@', [1, -1, 1j, -1j]):
- grid[pos + ori] = '#'
- grid[pos + ori + ori * 1j] = char
- return render(grid)
-
-
- def solve(text):
- grid, elements, keys = read_in(text)
- stacks = {k for k in elements if not k.isalnum()} - {'#', '.'}
- requirements, metric = precalc_moves(stacks, keys, elements, grid)
- states = [stacks]
- for _ in range(len(keys)):
- states = trim([
- state - {seq} | {seq + b}
- for state in states
- for seq in state
- for b, reqs in requirements[seq[-1]].items()
- if b not in seq and reqs.issubset(''.join(state))
- ], metric)
- best = min(states, key=metric)
- print(best)
- print(metric(best))
-
-
- text = sys.stdin.read()
- text = '''
- #############
- #g#f.D#..h#l#
- #F###e#E###.#
- #dCba...BcIJ#
- #####.@.#####
- #nK.L...G...#
- #M###N#H###.#
- #o#m..#i#jk.#
- #############
- '''
- solve(text)
- text = mod_grid(text)
- solve(text)
|