diff --git a/2024-python/output/__init__.py b/2024-python/output/__init__.py index be90eb8..ba3186c 100644 --- a/2024-python/output/__init__.py +++ b/2024-python/output/__init__.py @@ -23,6 +23,13 @@ DD = { "L": (0, -1), } +DDa = { + "^": (-1, 0), + ">": (0, 1), + "v": (1, 0), + "<": (0, -1), +} + # Adjacent relative positions including diagonals for 2D matrices, in the order NW, N, NE, W, E, SW, S, SE ADJ = [ (-1, -1), diff --git a/2024-python/output/day_21.py b/2024-python/output/day_21.py new file mode 100644 index 0000000..5fa1a51 --- /dev/null +++ b/2024-python/output/day_21.py @@ -0,0 +1,129 @@ +import re +from collections import deque, Counter, defaultdict +from heapq import heappop, heappush +from itertools import compress, combinations, chain, permutations +from functools import cache + +from output import matrix, D, DD, DDa, ADJ, ints, mhd, mdbg, vdbg, cw, ccw + +DKP = { + "^": (0, 1), + "A": (0, 2), + "<": (1, 0), + "v": (1, 1), + ">": (1, 2), +} + +NKP = { + "7": (0, 0), + "8": (0, 1), + "9": (0, 2), + "4": (1, 0), + "5": (1, 1), + "6": (1, 2), + "1": (2, 0), + "2": (2, 1), + "3": (2, 2), + "0": (3, 1), + "A": (3, 2), +} + + +def solve(data): + codes = data.split() + p1 = 0 + for code in codes: + seqlen = unwrap(code) + num = int(code[:-1]) + p1 += num * seqlen + p2 = None + return p1, p2 + + +def unwrap(dests): + seqlen = float("inf") + for num_path in press(dests, NKP): + for d0_path in press(num_path, DKP): + for d1_path in press(d0_path, DKP): + seqlen = min(seqlen, len(d1_path)) + return seqlen + + +def press(dests, pad): + s = "A" + P = [""] + for d in dests: + paths = bfs(tuple(pad.values()), pad[s], pad[d]) + ml = len(sorted(paths, key=lambda x: len(x))[0]) + sp = [p for p in paths if len(p) == ml] + nP = [] + for a in P: + for b in sp: + nP.append(a + b) + P = nP + s = d + P = sorted(P, key=lambda x: len(x)) + psl = len(P[0]) + return [p for p in P if len(p) == psl] + + +@cache +def bfs(grid, S, E): + seen = set() + Q = deque([(S, "<", "")]) + paths = [] + while Q: + pos, dn, path = Q.popleft() + if (pos, dn) in seen: + continue + if pos == E: + paths.append(path + "A") + continue + seen.add((pos, dn)) + y, x = pos + for dn, delta in DDa.items(): + dy, dx = delta + if (y + dy, x + dx) in grid: + Q.append(((y + dy, x + dx), dn, path + dn)) + return paths + + +if __name__ == "__main__": + import os + + # use dummy data + inp = """ + 029A + 980A + 179A + 456A + 379A + """.strip() + + """ + 68 * 29 + 60 * 980 + 68 * 179 + 64 * 456 + 64 * 379 + """ + + # uncomment to instead use stdin + # import sys; inp = sys.stdin.read().strip() + + # uncomment to use AoC provided puzzle input + with open("./input/21.txt", "r") as f: + inp = f.read().strip() + + # uncomment to do initial data processing shared by part 1-2 + p1, p2 = solve(inp) + + print(p1) + os.system(f"echo {p1} | wl-copy") + # print(p2) + # os.system(f"echo {p2} | wl-copy") + + # uncomment and replace 0 with actual output to refactor code + # and ensure nonbreaking changes + # assert p1 == 0 + # assert p2 == 0