| from collections import Counter | |||||
| def sum_counts(counts): | |||||
| """ | |||||
| >>> sum_counts([('a', 20), ('b', 10), ('a', 30)]) | |||||
| {'a': 50, 'b': 10} | |||||
| """ | |||||
| final = Counter() | |||||
| for k, v in counts: | |||||
| final[k] += v | |||||
| return final | |||||
| polymer, eqs = text.split('\n\n') | |||||
| mapping = dict(eq.split(' -> ') for eq in eqs.splitlines()) | |||||
| grow = {(a, b): ((a, x), (x, b)) for (a, b), x in mapping.items()} | |||||
| duos = Counter(duo for duo in zip(polymer, polymer[1:])) | |||||
| scores = {} | |||||
| for n in range(40): | |||||
| duos = sum_counts((new, N) for old, N in duos.items() for new in grow[old]) | |||||
| # account for double-counting when scoring, except at edges | |||||
| singles = sum_counts((k, N) for ab, N in duos.items() for k in ab) | |||||
| singles[polymer[0]] += 1 | |||||
| singles[polymer[-1]] += 1 | |||||
| xmax, *_, xmin = [N // 2 for _, N in singles.most_common()] | |||||
| scores[n + 1] = xmax - xmin | |||||
| ans1 = scores[10] | |||||
| ans2 = scores[40] |