2021-12-14 - Extended Polymerization
(original .ipynb)
Day 14 puzzle input is a description of a "polymer" (a string) and a number of transforms (a pair of polymer elements, and a new element that would be inserted between them after it is applied to the polymer) - mine is here. Part 1 involves transforming the polymer 10
times, finding the most and least common elements and subtracting them. Part 2 involves the same but 40
times.
from collections import defaultdict puzzle_input_str = open("puzzle_input/day14.txt").read() test_input_str = """NNCB CH -> B HH -> N CB -> H NH -> C HB -> C HC -> B HN -> C NN -> C BH -> H NC -> B NB -> B BN -> B BB -> N BC -> B CC -> N CN -> C""" # Apply 10 steps of pair insertion to the polymer template and find the most and least # common elements in the result. What do you get if you take the quantity of the most # common element and subtract the quantity of the least common element? def parse_input(input_str): polymer, rules_str = input_str.split("\n\n") rules = { k:v for k,v in [r.split(" -> ") for r in rules_str.split("\n")] } return polymer, rules def apply_rules(polymer, rules): a = polymer[0] new_polymer = [a] for i in range(1, len(polymer)): b = polymer[i] new_polymer.append(rules[a+b]) new_polymer.append(b) a = b return new_polymer def count_elements(polymer): count = defaultdict(lambda:0) for element in polymer: count[element] += 1 sorted_count = sorted(count.keys(), key=lambda e:count[e]) least, most = sorted_count[0], sorted_count[-1] return count[least], count[most] def part_one(input_str, steps = 10): polymer, rules = parse_input(input_str) while steps > 0: polymer = apply_rules(polymer, rules) steps -= 1 least, most = count_elements(polymer) return most - least assert 1588 == part_one(test_input_str) print("part one:", part_one(puzzle_input_str))
part one: 2975
def get_pairs(polymer): for i in range(0, len(polymer)): result = polymer[i:i + 2] # yuck if len(result) == 2: yield result def part_two(input_str, steps = 40): polymer_template, rules = parse_input(input_str) counts = defaultdict(lambda:0) for p in get_pairs(polymer_template): counts[p] += 1 while steps > 0: new_counts = defaultdict(lambda:0) for pair in counts: a, b = pair c = rules[a+b] new_counts[a+c] += counts[pair] new_counts[c+b] += counts[pair] counts = new_counts steps -= 1 totals = defaultdict(lambda:0) for pair in counts: a,b = pair totals[a] += counts[pair] totals[b] += counts[pair] sorted_totals = sorted(totals.keys(), key=lambda e:totals[e]) least, most = sorted_totals[0], sorted_totals[-1] # lol import math return int(math.ceil(totals[most]/2)) - int(math.ceil(totals[least]/2)) part_two(test_input_str, 40) print("part two:", part_two(puzzle_input_str))
part two: 3015383850689