| 🪨 | |||||
| 🌋 |
| DATA := $(BASE).dat | DATA := $(BASE).dat | ||||
| TEST := $(BASE).dtt | TEST := $(BASE).dtt | ||||
| save: | |||||
| git add . | |||||
| test `git log -1 --format=%s` == `cat VERSION` \ | |||||
| && git commit --amend --reuse-message=head \ | |||||
| || git commit -m `cat VERSION` | |||||
| git log -1 | |||||
| main: ${TEST} | main: ${TEST} | ||||
| echo 'test': | echo 'test': | ||||
| echo 'real:' | echo 'real:' | ||||
| cat ${DATA} | docker compose run --rm advent python -u ${CODE} | cat ${DATA} | docker compose run --rm advent python -u ${CODE} | ||||
| save: | |||||
| git add . | |||||
| test `git log -1 --format=%s` == `cat VERSION` \ | |||||
| && git commit --amend --reuse-message=head \ | |||||
| || git commit -m `cat VERSION` | |||||
| ${DATA} ${TEST}: | ${DATA} ${TEST}: | ||||
| # avoid spam in the lead up to the event | # avoid spam in the lead up to the event | ||||
| test ${DAY} -le `date +%d` || test ${YEAR} -lt `date +%Y` | test ${DAY} -le `date +%d` || test ${YEAR} -lt `date +%Y` |
| def solve(string, count): | |||||
| plain = [ln for ln in string.splitlines()] | |||||
| transposed = [''.join(ln) for ln in zip(*string.splitlines())] | |||||
| for grid, m in [(plain, 100), (transposed, 1)]: | |||||
| for idx in range(1, len(grid)): | |||||
| aa, bb = '\n'.join(grid[:idx][::-1]), '\n'.join(grid[idx:]) | |||||
| aa, bb = sorted([aa, bb], key=len) | |||||
| aa, bb = set(enumerate(aa)), set(enumerate(bb)) | |||||
| if len(aa - bb) == count: | |||||
| return idx * m | |||||
| strings = open(0).read().split('\n\n') | |||||
| print(sum(solve(string, 0) for string in strings)) | |||||
| print(sum(solve(string, 1) for string in strings)) |
| def parse(string): | |||||
| return { | |||||
| complex(x, y): val | |||||
| for y, row in enumerate(string.splitlines()) | |||||
| for x, val in enumerate(row) | |||||
| } | |||||
| def render(grid): | |||||
| xmin, *_, xmax = sorted({int(p.real) for p in grid}) | |||||
| ymin, *_, ymax = sorted({int(p.imag) for p in grid}) | |||||
| for y in range(ymin, ymax + 1): | |||||
| for x in range(xmin, xmax + 1): | |||||
| print(grid[complex(x, y)], end='') | |||||
| print() | |||||
| def rotate(grid, angle): | |||||
| swaps_ongoing = 1 | |||||
| while swaps_ongoing: | |||||
| swaps_ongoing = 0 | |||||
| for pos, val in grid.items(): | |||||
| if val == 'O': | |||||
| while grid.get(pos + angle) == '.': | |||||
| pos, old = pos + angle, pos | |||||
| grid[pos], grid[old] = val, '.' | |||||
| swaps_ongoing += 1 | |||||
| return grid | |||||
| def calc_load(state): | |||||
| return int(sum(height - p.imag + 1 for p, val in state.items() if val == 'O')) | |||||
| text = open(0).read() | |||||
| grid = parse(text) | |||||
| height = max(p.imag for p in grid) | |||||
| print(calc_load(rotate(grid, -1j))) | |||||
| seq = [] | |||||
| while True: | |||||
| signature = frozenset(grid.items()) | |||||
| if signature in seq: | |||||
| break | |||||
| seq.append(signature) | |||||
| for angle in [-1j, -1, 1j, 1]: | |||||
| grid = rotate(grid, angle) | |||||
| prelude = seq.index(signature) | |||||
| cycle_length = len(seq) - prelude | |||||
| print(calc_load(dict(seq[prelude + (1_000_000_000 - prelude) % cycle_length]))) |