From e1c56b22578a1e530152e8722c65ead4866a6990 Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Sat, 10 May 2025 12:50:24 +0100 Subject: [PATCH] 2017: d16: ex2: add solution --- 2017/d16/ex2/ex2.py | 82 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100755 2017/d16/ex2/ex2.py diff --git a/2017/d16/ex2/ex2.py b/2017/d16/ex2/ex2.py new file mode 100755 index 0000000..d65972d --- /dev/null +++ b/2017/d16/ex2/ex2.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python + +import sys +from typing import NamedTuple + + +class Spin(NamedTuple): + n: int + + +class Exchange(NamedTuple): + a: int + b: int + + +class Partner(NamedTuple): + a: str + b: str + + +Move = Spin | Exchange | Partner + +Programs = tuple[str, ...] + + +def solve(input: str) -> str: + def parse_move(input: str) -> Move: + if input[0] == "s": + return Spin(int(input[1:])) + if input[0] == "x": + return Exchange(*map(int, input[1:].split("/"))) + if input[0] == "p": + return Partner(*input[1:].split("/")) + assert False # Sanity check + + def parse(input: str) -> list[Move]: + return [parse_move(move) for move in input.strip().split(",")] + + def apply_move(programs: Programs, move: Move) -> Programs: + match move: + case Spin(n): + return programs[-n:] + programs[:-n] + case Exchange(a, b): + tmp = list(programs) + tmp[a], tmp[b] = tmp[b], tmp[a] + return tuple(tmp) + case Partner(a, b): + ia, ib = programs.index(a), programs.index(b) + tmp = list(programs) + tmp[ia], tmp[ib] = tmp[ib], tmp[ia] + return tuple(tmp) + + def do_dance(programs: Programs, moves: list[Move]) -> Programs: + t = 0 + cache = {(programs, 0): 0} + TOTAL_MOVES = 1000000000 * len(moves) + while t < TOTAL_MOVES: + programs = apply_move(programs, moves[t % len(moves)]) + t += 1 + key = (programs, t % len(moves)) + if (previous_t := cache.get(key)) is not None: + cycle_length = t - previous_t + num_cycles = (TOTAL_MOVES - t) // cycle_length + t += num_cycles * cycle_length + else: + cache[key] = t + + return programs + + moves = parse(input) + programs = tuple(chr(ord("a") + i) for i in range(16)) + programs = do_dance(programs, moves) + return "".join(programs) + + +def main() -> None: + input = sys.stdin.read() + print(solve(input)) + + +if __name__ == "__main__": + main()