69 lines
2.1 KiB
Python
Executable File
69 lines
2.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import sys
|
|
from collections import defaultdict, Counter
|
|
from typing import DefaultDict, Mapping
|
|
from copy import deepcopy
|
|
|
|
|
|
def apply_rules(template: str, rules: Mapping[str, str]) -> str:
|
|
# sliding window babey
|
|
new = ""
|
|
for i in range(len(template) - 1):
|
|
new += template[i] + rules[template[i : i + 2]]
|
|
return new + template[-1]
|
|
|
|
|
|
def part1(template: str, rules: Mapping[str, str]):
|
|
for i in range(10):
|
|
template = apply_rules(template, rules)
|
|
counts: DefaultDict[str, int] = defaultdict(lambda: 0)
|
|
for c in template:
|
|
counts[c] += 1
|
|
counts_sorted = sorted(counts.items(), key=lambda pair: pair[1])
|
|
_, least = counts_sorted[0]
|
|
_, most = counts_sorted[-1]
|
|
print(most - least)
|
|
|
|
|
|
def part2(template: str, rules: Mapping[str, str]):
|
|
# Apply rules with counts instead of building a string
|
|
counts: Counter = Counter()
|
|
|
|
for i in range(len(template) - 1):
|
|
counts[template[i : i + 2]] += 1
|
|
|
|
for _ in range(40):
|
|
new_counts: Counter = Counter()
|
|
for pair, count in counts.items():
|
|
# Create the two new pairs, and remove the old one
|
|
rule = rules[pair]
|
|
p1 = pair[0] + rule
|
|
p2 = rule + pair[1]
|
|
# Subtract from this pair, and then add the new ones
|
|
new_counts[p1] += counts[pair]
|
|
new_counts[p2] += counts[pair]
|
|
counts = new_counts
|
|
# Count all the letters, only using the first character.
|
|
# If we count the second character, we double-count.
|
|
letters: Counter = Counter()
|
|
for pair in counts:
|
|
letters[pair[0]] += counts[pair]
|
|
# We just need to count the last character in the original template - since this never changes.
|
|
letters[template[-1]] += 1
|
|
print(max(letters.values()) - min(letters.values()))
|
|
|
|
|
|
template = sys.stdin.readline().strip()
|
|
# blank
|
|
sys.stdin.readline()
|
|
rules = {
|
|
rule: translate.strip()
|
|
for rule, translate in map(lambda line: line.split(" -> "), sys.stdin)
|
|
}
|
|
|
|
|
|
print("Part 1")
|
|
part1(template, rules)
|
|
print("Part 2")
|
|
part2(template, rules)
|