import sys from typing import TypeAlias RockGrid: TypeAlias = list[list[str]] rocks0 = [list(line) for line in sys.stdin.read().splitlines()] def slide_rocks_top(rocks: RockGrid) -> RockGrid: top = [0 if c == "." else 1 for c in rocks[0]] for row in range(1, len(rocks)): for col in range(len(rocks[0])): match rocks[row][col]: case "O": if top[col] != row: rocks[top[col]][col] = "O" rocks[row][col] = "." top[col] = top[col] + 1 case "#": top[col] = row + 1 case _: pass return rocks def cycle(rocks: RockGrid) -> RockGrid: for _ in range(4): rocks = slide_rocks_top(rocks) rocks = [ [rocks[len(rocks) - j - 1][i] for j in range(len(rocks))] for i in range(len(rocks[0])) ] return rocks rocks = slide_rocks_top([[c for c in r] for r in rocks0]) # part 1 answer_1 = sum( (len(rocks) - i) * sum(1 for c in row if c == "O") for i, row in enumerate(rocks) ) print(f"answer 1 is {answer_1}") # part 2 rocks = rocks0 N = 1000000000 cycles: list[RockGrid] = [] i_cycle: int = -1 for i_cycle in range(N): rocks = cycle(rocks) if any(rocks == c for c in cycles): break cycles.append([[c for c in r] for r in rocks]) cycle_start = next(i for i in range(len(cycles)) if (rocks == cycles[i])) cycle_length = i_cycle - cycle_start ci = cycle_start + (N - cycle_start) % cycle_length - 1 answer_2 = sum( (len(rocks) - i) * sum(1 for c in row if c == "O") for i, row in enumerate(cycles[ci]) ) print(f"answer 2 is {answer_2}")