🪨 | |||||
🌋 |
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]))) |