diff --git a/2021/14/README.md b/2021/14/README.md new file mode 100644 index 0000000..c481078 --- /dev/null +++ b/2021/14/README.md @@ -0,0 +1,68 @@ +# 2021 Day 14: Extended Polymerization +Copyright (c) Eric Wastl +#### [Direct Link](https://adventofcode.com/2021/day/14) + +## Part 1 + +The incredible pressures at this depth are starting to put a strain on your submarine. The submarine has [polymerization](https://en.wikipedia.org/wiki/Polymerization) equipment that would produce suitable materials to reinforce the submarine, and the nearby volcanically-active caves should even have the necessary input elements in sufficient quantities. + +The submarine manual contains instructions for finding the optimal polymer formula; specifically, it offers a **polymer template** and a list of **pair insertion** rules (your puzzle input). You just need to work out what polymer would result after repeating the pair insertion process a few times. + +For example: + +``` +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 +``` + +The first line is the **polymer template** - this is the starting point of the process. + +The following section defines the **pair insertion** rules. A rule like `AB -> C` means that when elements `A` and `B` are immediately adjacent, element `C` should be inserted between them. These insertions all happen simultaneously. + +So, starting with the polymer template `NNCB`, the first step simultaneously considers all three pairs: + +- The first pair (`NN`) matches the rule `NN` -> `C`, so element `C` is inserted between the first `N` and the second `N`. +- The second pair (`NC`) matches the rule `NC` -> `B`, so element `B` is inserted between the `N` and the `C`. +- The third pair (`CB`) matches the rule `CB -> H`, so element `H is inserted between the `C` and the `B`. + +Note that these pairs overlap: the second element of one pair is the first element of the next pair. Also, because all pairs are considered simultaneously, inserted elements are not considered to be part of a pair until the next step. + +After the first step of this process, the polymer becomes `NCNBCHB`. + +Here are the results of a few steps using the above rules: + +``` +Template: NNCB +After step 1: NCNBCHB +After step 2: NBCCNBBBCBHCB +After step 3: NBBBCNCCNBBNBNBBCHBHHBCHB +After step 4: NBBNBNBBCCNBCNCCNBBNBBNBBBNBBNBBCBHCBHHNHCBBCBHCB +``` + +This polymer grows quickly. After step 5, it has length 97; After step 10, it has length 3073. After step 10, `B` occurs 1749 times, `C` occurs 298 times, `H` occurs 161 times, and `N` occurs 865 times; taking the quantity of the most common element (B, 1749) and subtracting the quantity of the least common element (`H`, 161) produces `1749 - 161 = 1588`. + +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?** + +## Part 2 + +The resulting polymer isn't nearly strong enough to reinforce the submarine. You'll need to run more steps of the pair insertion process; a total of **40 steps** should do it. + +In the above example, the most common element is `B` (occurring `2192039569602` times) and the least common element is `H` (occurring `3849876073` times); subtracting these produces **`2188189693529`**. + +Apply **40** 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?** diff --git a/2021/14/code.py b/2021/14/code.py new file mode 100644 index 0000000..212b1c0 --- /dev/null +++ b/2021/14/code.py @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) 2021 Akumatic +# +# https://adventofcode.com/2021/day/14 + +def read_file(filename: str = "input.txt") -> tuple: + with open(f"{__file__.rstrip('code.py')}{filename}", "r") as f: + lines = [line for line in f.read().strip().split("\n")] + template = lines[0] + rules = {x[0]: x[1] for x in (line.split(" -> ") for line in lines[2:])} + return template, rules + +def add_to_dict(d: dict, key: str, val: int = 1): + if key not in d: + d[key] = val + else: + d[key] += val + +def count(polymer: str, rules: dict, iterations: int) -> dict: + pairs = dict() + for i in range(len(polymer) - 1): + add_to_dict(pairs, polymer[i] + polymer[i+1]) + + for _ in range(iterations): + tmp = dict() + for pair in pairs: + add_to_dict(tmp, pair[0] + rules[pair], pairs[pair]) + add_to_dict(tmp, rules[pair] + pair[1], pairs[pair]) + pairs = tmp + + elements = dict() + for pair in pairs: + add_to_dict(elements, pair[0], pairs[pair]) + add_to_dict(elements, polymer[-1]) + return elements + +def part1(template: str, insertion_rules: dict) -> int: + letters = count(template, insertion_rules, 10) + return max(letters.values()) - min(letters.values()) + +def part2(template: str, insertion_rules: dict) -> int: + letters = count(template, insertion_rules, 40) + return max(letters.values()) - min(letters.values()) + +if __name__ == "__main__": + vals = read_file() # vals[0] is the template, vals[1] the insertion rules + print(f"Part 1: {part1(*vals)}") + print(f"Part 2: {part2(*vals)}") diff --git a/2021/14/input.txt b/2021/14/input.txt new file mode 100644 index 0000000..cc9b577 --- /dev/null +++ b/2021/14/input.txt @@ -0,0 +1,102 @@ +HBCHSNFFVOBNOFHFOBNO + +HF -> O +KF -> F +NK -> F +BN -> O +OH -> H +VC -> F +PK -> B +SO -> B +PP -> H +KO -> F +VN -> S +OS -> B +NP -> C +OV -> C +CS -> P +BH -> P +SS -> P +BB -> H +PH -> V +HN -> F +KV -> H +HC -> B +BC -> P +CK -> P +PS -> O +SH -> N +FH -> N +NN -> P +HS -> O +CB -> F +HH -> F +SB -> P +NB -> F +BO -> V +PN -> H +VP -> B +SC -> C +HB -> H +FP -> O +FC -> H +KP -> B +FB -> B +VK -> F +CV -> P +VF -> V +SP -> K +CC -> K +HV -> P +NC -> N +VH -> K +PF -> P +PB -> S +BF -> K +FF -> C +FV -> V +KS -> H +VB -> F +SV -> F +HO -> B +FN -> C +SN -> F +OB -> N +KN -> P +BV -> H +ON -> N +NF -> S +OF -> P +NV -> S +VS -> C +OO -> C +BP -> H +BK -> N +CP -> N +PC -> K +CN -> H +KB -> B +BS -> P +KK -> P +SF -> V +CO -> V +CH -> P +FO -> B +FS -> F +VO -> H +NS -> F +KC -> H +VV -> K +NO -> P +OK -> F +PO -> V +FK -> H +OP -> H +PV -> N +CF -> P +NH -> K +SK -> O +KH -> P +HP -> V +OC -> V +HK -> F diff --git a/2021/14/solution.txt b/2021/14/solution.txt new file mode 100644 index 0000000..014c9b5 --- /dev/null +++ b/2021/14/solution.txt @@ -0,0 +1,2 @@ +Part 1: 3408 +Part 2: 3724343376942 \ No newline at end of file diff --git a/2021/14/test_code.py b/2021/14/test_code.py new file mode 100644 index 0000000..7961176 --- /dev/null +++ b/2021/14/test_code.py @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) 2021 Akumatic + +from code import part1, part2, read_file, count + +def count_chars(s: str) -> dict: + cnt = dict() + for c in s: + if c in cnt: + cnt[c] += 1 + else: + cnt[c] = 1 + return cnt + +def test(): + vals = read_file("test_input.txt") + assert count(vals[0], vals[1], 1) == count_chars("NCNBCHB") + assert count(vals[0], vals[1], 2) == count_chars("NBCCNBBBCBHCB") + assert count(vals[0], vals[1], 3) == count_chars("NBBBCNCCNBBNBNBBCHBHHBCHB") + assert count(vals[0], vals[1], 4) == count_chars("NBBNBNBBCCNBCNCCNBBNBBNBBBNBBNBBCBHCBHHNHCBBCBHCB") + print("Passed Counting") + + elements = count(vals[0], vals[1], 10) + assert elements == {"B": 1749, "C": 298, "H": 161, "N": 865} + assert part1(*vals) == 1588 + print("Passed Part 1") + + elements = count(vals[0], vals[1], 40) + assert elements["B"] == 2192039569602 + assert elements["H"] == 3849876073 + assert part2(*vals) == 2188189693529 + print("Passed Part 2") + +if __name__ == "__main__": + test() diff --git a/2021/14/test_input.txt b/2021/14/test_input.txt new file mode 100644 index 0000000..b5594dd --- /dev/null +++ b/2021/14/test_input.txt @@ -0,0 +1,18 @@ +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 diff --git a/2021/README.md b/2021/README.md index 103192c..20095ed 100644 --- a/2021/README.md +++ b/2021/README.md @@ -28,7 +28,7 @@ Collect stars by solving puzzles. Two puzzles will be made available on each day | 11 | :white_check_mark: | :white_check_mark: | [Solution](11/code.py) | [Day 11](https://adventofcode.com/2021/day/11) | | 12 | :white_check_mark: | :white_check_mark: | [Solution](12/code.py) | [Day 12](https://adventofcode.com/2021/day/12) | | 13 | :white_check_mark: | :white_check_mark: | [Solution](13/code.py) | [Day 13](https://adventofcode.com/2021/day/13) | -| 14 | | | | | +| 14 | :white_check_mark: | :white_check_mark: | [Solution](14/code.py) | [Day 14](https://adventofcode.com/2021/day/14) | | 15 | | | | | | 16 | | | | | | 17 | | | | |