#!/usr/bin/env python3 import sys, math from itertools import product DIR = { ('A', '>'): ['vA'], ('A', '^'): ['', '>'): ['A'], ('^', 'A'): ['>A'], ('^', '>'): ['v>A', '>vA'], ('^', 'v'): ['vA'], ('^', '<'): ['v>^A'], ('<', '^'): ['>^A'], ('<', 'v'): ['>A'], ('<', '>'): ['>>A'], ('v', 'A'): ['>^A', '^>A'], ('v', '^'): ['^A'], ('v', '<'): [''): ['>A'], ('>', 'A'): ['^A'], ('>', '<'): ['<', '^'): ['<^A', '^', 'v'): ['': (0,1), '<': (0,-1)} dy = e[0]-s[0] dx = e[1]-s[1] opt = ['^'] * dy + ['v'] * -dy + ['<'] * -dx + ['>'] * dx for o in [tuple(opt), tuple(reversed(opt))]: s, e = pad[start], pad[end] gap = False for step in list(o): s = s[0] + d[step][0], s[1] + d[step][1] if s == (0,0): gap = True if not gap: yield ''.join(o+('A',)) def numeric(code): strings = [''] prev = 'A' for key in list(code): strings = [s1+s2 for (s1,s2) in product(strings,[opt for opt in options(prev, key, NUM)])] prev = key return strings # reddit solution... (prevKey is 'A' the first time) def buildSeq(keys, index, prevKey, currPath, result): if index == len(keys): result.append(currPath) return for path in DIR[(prevKey,keys[index])]: buildSeq(keys, index+1, keys[index], currPath + path, result) @memo def shortestSeq(keys, depth): if depth == 0: return len(keys) total = 0 subKeys = keys.split('A') for subKey in subKeys[:-1]: seqs = [] buildSeq(subKey+'A', 0, 'A', '', seqs) minimum = min([shortestSeq(seq, depth-1) for seq in seqs]) total += minimum return total if __name__ == '__main__': codes = [line.strip('\n') for line in open(sys.argv[1])] res1, res2 = 0, 0 for code in codes: dirs = set(numeric(code)) l1, l2 = math.inf, math.inf for d in dirs: l1 = min(shortestSeq(d,2), l1) res1 += l1 * int(code[:-1]) for d in dirs: l2 = min(shortestSeq(d,25), l2) res2 += l2 * int(code[:-1]) # challenge 1 print(f"challenge 1:\n{res1}\n") # challenge 2 print(f"challenge 2:\n{res2}")