80 lines
1.9 KiB
Python
80 lines
1.9 KiB
Python
import re
|
|
|
|
|
|
def to_int(bitlist):
|
|
out = 0
|
|
for bit in bitlist:
|
|
out = out * 2 + bit
|
|
return out
|
|
|
|
|
|
def grow(init, num_gens, progress=False):
|
|
first, last = min(init), max(init)
|
|
current_gen = set(init)
|
|
for g in range(num_gens):
|
|
next_gen = set()
|
|
for i in range(first - 2, last + 3):
|
|
key = to_int(1 if b in current_gen else 0 for b in range(i - 2, i + 3))
|
|
if key in positives:
|
|
next_gen.add(i)
|
|
if i < first:
|
|
first = i
|
|
if i > last:
|
|
last = i
|
|
current_gen = next_gen
|
|
|
|
if progress:
|
|
print('Generations:', g + 1, end='\r')
|
|
|
|
if progress: print('Generations:', g + 1)
|
|
return current_gen
|
|
|
|
|
|
def test(n):
|
|
pots = grow(initial, n)
|
|
first, last = min(pots), max(pots)
|
|
chars = []
|
|
for i in range(first - 1, last + 2):
|
|
chars.append('#' if i in pots else '.')
|
|
print(''.join(chars))
|
|
|
|
|
|
with open('data/12.txt') as f:
|
|
initial = re.search('[#.]+', next(f)).group(0)
|
|
initial = {i for i, p in enumerate(initial) if p == '#'}
|
|
next(f)
|
|
|
|
positives, negatives = set(), set()
|
|
for line in f:
|
|
state, result = line.strip().split(' => ')
|
|
s = to_int(int(c == '#') for c in state)
|
|
if result == '#':
|
|
positives.add(s)
|
|
else:
|
|
negatives.add(s)
|
|
|
|
|
|
pots = grow(initial, 20)
|
|
print(f'Part 1: {sum(pots)}\n')
|
|
|
|
|
|
# find pattern and exploit
|
|
first_stable = 0
|
|
prev_gen = []
|
|
for i in range(1, 1000):
|
|
current_gen = sorted(grow(initial, i))
|
|
if current_gen == [x + 1 for x in prev_gen]:
|
|
first_stable = i - 1
|
|
break
|
|
else:
|
|
prev_gen = current_gen
|
|
magic_number = sum(prev_gen)
|
|
|
|
|
|
def cheat(num_gens):
|
|
if num_gens < first_stable:
|
|
raise RuntimeError("Can't cheat.")
|
|
return magic_number + (num_gens - first_stable) * len(prev_gen)
|
|
|
|
print(f'Part 2: {cheat(5 * 10 ** 10)}\n')
|