21_keypad.py 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940
  1. #!/usr/bin/env python3
  2. import sys
  3. from functools import cache
  4. from itertools import pairwise
  5. NUMERIC = '789', '456', '123', ' 0A'
  6. DIRECTIONAL = ' ^A', '<v>'
  7. def walk(keypad, x, y, path):
  8. for direction in path:
  9. neighbors = (x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)
  10. x, y = neighbors['<>^v'.index(direction)]
  11. yield keypad[y][x]
  12. def paths_between(keypad, start, end):
  13. x1, y1 = next((x, y) for y, row in enumerate(keypad)
  14. for x, key in enumerate(row) if key == start)
  15. x2, y2 = next((x, y) for y, row in enumerate(keypad)
  16. for x, key in enumerate(row) if key == end)
  17. hor = '<>'[x2 > x1] * abs(x2 - x1)
  18. ver = '^v'[y2 > y1] * abs(y2 - y1)
  19. return tuple(path + 'A' for path in {hor + ver, ver + hor}
  20. if ' ' not in walk(keypad, x1, y1, path))
  21. @cache
  22. def cost_between(keypad, start, end, links):
  23. return min(cost(DIRECTIONAL, path, links - 1)
  24. for path in paths_between(keypad, start, end)) if links else 1
  25. @cache
  26. def cost(keypad, keys, links):
  27. return sum(cost_between(keypad, a, b, links)
  28. for a, b in pairwise('A' + keys))
  29. def complexity(code, robots):
  30. return cost(NUMERIC, code, robots + 1) * int(code[:-1])
  31. codes = sys.stdin.read().split()
  32. print(sum(complexity(code, 2) for code in codes))
  33. print(sum(complexity(code, 25) for code in codes))