diff options
author | Tomasz Kramkowski <tomasz@kramkow.ski> | 2023-12-23 23:16:55 +0100 |
---|---|---|
committer | Tomasz Kramkowski <tomasz@kramkow.ski> | 2023-12-23 23:16:55 +0100 |
commit | 74dfba0d94d9590386a983fc8014666d33aec534 (patch) | |
tree | 2829d74ab553e2086cc975e1edca5810b9802005 | |
parent | e9602b3dc2bf06cc2263e22cd3b8caa0a833e3f6 (diff) | |
download | aoc2023-74dfba0d94d9590386a983fc8014666d33aec534.tar.gz aoc2023-74dfba0d94d9590386a983fc8014666d33aec534.tar.xz aoc2023-74dfba0d94d9590386a983fc8014666d33aec534.zip |
day 21 disaster
-rw-r--r-- | 21.py | 132 |
1 files changed, 132 insertions, 0 deletions
@@ -0,0 +1,132 @@ +from collections import deque +from itertools import groupby, islice +from sys import stdin + +inp = [line.rstrip() for line in stdin] + +for y, l in enumerate(inp): + try: + sx, sy = l.index("S"), y + break + except ValueError: + pass +else: + raise ValueError + + +def all_equal(iterable): + g = groupby(iterable) + return next(g, True) and not next(g, False) + + +def solve(inp: list[str], start: tuple[int, int]) -> list[int]: + queue = deque() + queue.append((start[0], start[1], 0)) + seen = set() + history = list() + while queue: + px, py, depth = queue.popleft() + if (px, py) in seen: + continue + seen.add((px, py)) + if len(history) <= depth: + history.append(0) + history[depth] += 1 + for dx in (-1, 1): + nx = px + dx + if 0 <= nx < len(inp[0]) and inp[py][nx] != "#": + queue.append((nx, py, depth + 1)) + for dy in (-1, 1): + ny = py + dy + if 0 <= ny < len(inp) and inp[ny][px] != "#": + queue.append((px, ny, depth + 1)) + return history + + +assert len(inp) == len(inp[0]) + +nw = solve(inp, (len(inp[0]) - 1, len(inp) - 1)) +n = solve(inp, (sx, len(inp) - 1)) +ne = solve(inp, (0, len(inp) - 1)) +w = solve(inp, (len(inp[0]) - 1, sy)) +c = solve(inp, (sx, sy)) +e = solve(inp, (0, sy)) +sw = solve(inp, (len(inp[0]) - 1, 0)) +s = solve(inp, (sx, 0)) +se = solve(inp, (0, 0)) + + +def sum_offt(a: list[int], offset: int, point: int | None = None) -> int: + if point is None: + point = len(a) + else: + point += 1 + return sum(islice(a, offset, point, 2)) + + +def closed(target: int) -> int: + base_offt = target % 2 + radius = (len(inp) - 1) // 2 + + arm_len = max(target - len(inp) - radius - 1, 0) // len(inp) + a_arms_offt = (base_offt + radius + 1) % 2 + a_arms_count = (arm_len + 1) // 2 + b_arms_offt = (a_arms_offt + 1) % 2 + b_arms_count = arm_len // 2 + arms_sum = sum( + sum_offt(d, a_arms_offt) * a_arms_count + + sum_offt(d, b_arms_offt) * b_arms_count + for d in (n, e, s, w) + ) + + corner_len = max(target - len(inp), 0) // len(inp) + e_corner_count = (corner_len // 2) ** 2 + o_corner_len = max(corner_len - 1, 0) // 2 + o_corner_count = o_corner_len * (o_corner_len + 1) + corner_sum = sum( + sum_offt(d, base_offt) * e_corner_count + + sum_offt(d, (base_offt + 1) % 2) * o_corner_count + for d in (nw, ne, sw, se) + ) + + a_tips_point = max(target - radius - 1, 0) % (2 * len(inp)) + a_tips_offt = (radius + base_offt + 1) % 2 + a_tips_count = 1 if target + radius >= len(inp) else 0 + b_tips_point = max(target - radius - len(inp) - 1, 0) % (2 * len(inp)) + b_tips_offt = (radius + base_offt) % 2 + b_tips_count = 1 if target - radius > len(inp) else 0 + + tips_sum = sum( + sum_offt(d, a_tips_offt, a_tips_point) * a_tips_count + + sum_offt(d, b_tips_offt, b_tips_point) * b_tips_count + for d in (n, e, s, w) + ) + + a_sides_point = max(target - len(inp), 0) % (2 * len(inp)) + a_sides_count = max((target + len(inp) - 1) // (2 * len(inp)) * 2 - 1, 0) + a_sides_offt = base_offt + a_sides_sum = ( + sum(sum_offt(d, a_sides_offt, a_sides_point) for d in (nw, ne, sw, se)) + * a_sides_count + ) + + b_sides_point = target % (2 * len(inp)) + b_sides_count = max(target - 1, 0) // (2 * len(inp)) * 2 + b_sides_offt = (base_offt + 1) % 2 + b_sides_sum = ( + sum(sum_offt(d, b_sides_offt, b_sides_point) for d in (nw, ne, sw, se)) + * b_sides_count + ) + + return ( + sum_offt(c, base_offt, target) + + corner_sum + + arms_sum + + tips_sum + + a_sides_sum + + b_sides_sum + ) + + +print(closed(64)) +print(closed(26501365)) |