🪨 |
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': | ||||
cat ${TEST} | docker compose run --rm advent python -u ${CODE} | cat ${TEST} | docker compose run --rm advent python -u ${CODE} |
import itertools | |||||
def star_dist(a, b, N): | |||||
(xa, xb), (ya, yb) = map(sorted, zip(a, b)) | |||||
sx = sum(xa < x < xb for x in xs) | |||||
sy = sum(ya < y < yb for y in ys) | |||||
return (xb - xa) + (yb - ya) + (N - 1) * (sx + sy) | |||||
text = open(0).read() | |||||
ys = {i for i, ln in enumerate(text.splitlines()) if set(ln) == {'.'}} | |||||
xs = {i for i, ln in enumerate(zip(*text.splitlines())) if set(ln) == {'.'}} | |||||
stars = {(x, y) for y, row in enumerate(text.splitlines()) for x, val in enumerate(row) if val == '#'} | |||||
print(sum(star_dist(a, b, 2) for a, b in itertools.combinations(stars, 2))) | |||||
print(sum(star_dist(a, b, 1_000_000) for a, b in itertools.combinations(stars, 2))) |
import functools | |||||
import re | |||||
@functools.lru_cache(maxsize=None) | |||||
def get_combos(pattern, ns): | |||||
out = 0 | |||||
if not ns: | |||||
new = '_' * len(pattern) | |||||
if re.fullmatch(pattern, new): | |||||
out += 1 | |||||
else: | |||||
n, *ns = ns | |||||
i_max = len(pattern) - sum(ns) - len(ns) - n + 1 | |||||
for i in range(i_max): | |||||
new = '_' * i + '#' * n + '_' * (len(pattern) > i + n) | |||||
if re.fullmatch(pattern[:len(new)], new): | |||||
out += get_combos(pattern[len(new):], tuple(ns)) | |||||
return out | |||||
def combos(line, N=1): | |||||
pattern, ns = line.split() | |||||
# expand | |||||
pattern = '?'.join([pattern] * N) | |||||
ns = ','.join([ns] * N) | |||||
# parse | |||||
pattern = pattern.replace('.', '_').replace('?', '.') | |||||
ns = [int(n) for n in ns.split(',')] | |||||
return get_combos(pattern, tuple(ns)) | |||||
text = open(0).read() | |||||
print(sum(combos(line) for line in text.splitlines())) | |||||
print(sum(combos(line, 5) for line in text.splitlines())) |