From d84673a7795e72f1a79c13f86a63fd8d4d5fccaa Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Tue, 14 Dec 2021 08:13:01 +0000 Subject: [PATCH] Add 2021 day 14 puzzles --- 2021/puzzle-14-01.cc | 71 ++++++++++++++++++++++++++++++++++++ 2021/puzzle-14-02.cc | 87 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 2021/puzzle-14-01.cc create mode 100644 2021/puzzle-14-02.cc diff --git a/2021/puzzle-14-01.cc b/2021/puzzle-14-01.cc new file mode 100644 index 0000000..73df6ae --- /dev/null +++ b/2021/puzzle-14-01.cc @@ -0,0 +1,71 @@ +#include +#include +#include + +using PolymerMap = std::map, char>; + +template +void expand1(char c1, char c2, PolymerMap const& polymers, unsigned current_depth, + unsigned max_depth, Fn action) +{ + if (current_depth == max_depth) { + action(c1); + return; + } + + auto it{polymers.find({c1, c2})}; + if (it == polymers.end()) { + action(c1); + return; + } + expand1(c1, it->second, polymers, current_depth + 1, max_depth, action); + expand1(it->second, c2, polymers, current_depth + 1, max_depth, action); +} + +template +void expand(std::string const& str, unsigned max_depth, PolymerMap const& polymers, Fn action) +{ + for (std::size_t idx{0}; idx < str.size() - 1; ++idx) { + expand1(str[idx], str[idx + 1], polymers, 0, max_depth, action); + } + action(str.back()); +} + +auto main() -> int +{ + std::string initial; + std::string line; + PolymerMap polymers; + + if (!std::getline(std::cin, initial)) { + std::cerr << "Unable to read initial lines.\n"; + return 1; + } + + if (!std::getline(std::cin, line) && !line.empty()) { + std::cerr << "Missing empty line.\n"; + return 1; + } + + while (std::getline(std::cin, line) && !line.empty()) { + polymers.insert({{line[0], line[1]}, line.back()}); + } + + std::map counts; + auto action = [&counts](char c) { + auto [it, success] = counts.insert({c, 0}); + (it->second)++; + }; + + expand(initial, 10, polymers, action); + + for (auto const& c : counts) { + std::cout << c.first << " -> " << c.second << '\n'; + } + auto [min, max] = std::minmax_element( + counts.begin(), counts.end(), [](auto const& l, auto const& r) { return l.second < r.second; }); + std::cout << "Min: " << min->first << " -> " << min->second << '\n'; + std::cout << "Max: " << max->first << " -> " << max->second << '\n'; + std::cout << "Difference: " << max->second - min->second << '\n'; + return 0; +} diff --git a/2021/puzzle-14-02.cc b/2021/puzzle-14-02.cc new file mode 100644 index 0000000..a7d9de1 --- /dev/null +++ b/2021/puzzle-14-02.cc @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include + +using Starter = std::pair; +using PolymerMap = std::map; + +auto main() -> int +{ + std::string initial; + std::string line; + PolymerMap polymers; + + if (!std::getline(std::cin, initial)) { + std::cerr << "Unable to read initial lines.\n"; + return 1; + } + + if (!std::getline(std::cin, line) && !line.empty()) { + std::cerr << "Missing empty line.\n"; + return 1; + } + + while (std::getline(std::cin, line) && !line.empty()) { + polymers.insert({{line[0], line[1]}, line.back()}); + } + + /* Work out what reactions we have in the first step. */ + std::map counts; + for (std::size_t idx{0}; idx < initial.size() - 1; ++idx) { + auto [it, success] = counts.insert({{initial[idx], initial[idx + 1]}, 0}); + ++(it->second); + } + + /* Then for each of the following steps work out the reactions that would produce, and how many + * Note we don't care about the order they're applied here. + */ + for (unsigned i = 0; i < 40; ++i) { + std::map updated_counts; + auto a{std::accumulate(counts.begin(), counts.end(), std::uint64_t{0}, + [](auto a, auto const& it) { return a + it.second; })}; + std::cout << "Step " << i << " size " << a << '\n'; + for (auto const& c : counts) { + auto it{polymers.find(c.first)}; + if (it == polymers.end()) { + auto [it2, success] = updated_counts.insert({c.first, 0}); + it2->second += c.second; + } + else { + auto [it3, success3] = updated_counts.insert({{c.first.first, it->second}, 0}); + it3->second += c.second; + auto [it4, success4] = updated_counts.insert({{it->second, c.first.second}, 0}); + it4->second += c.second; + } + } + std::swap(counts, updated_counts); + } + + /* Now count up have many for each letter we have. We only count the first letter of each + * molecule as the second letter will form the start of the next molecule. Well except for the + * last element. + */ + std::map letter_counts; + for (auto const& c : counts) { + auto [it, success] = letter_counts.insert({c.first.first, 0}); + it->second += c.second; + } + /* So add the last letter. */ + auto [it, success] = letter_counts.insert({initial.back(), 0}); + ++(it->second); + + for (auto const& c : counts) { + std::cout << c.first.first << c.first.second << " -> " << c.second << '\n'; + } + for (auto const& c : letter_counts) { + std::cout << c.first << " -> " << c.second << '\n'; + } + auto [min, max] = + std::minmax_element(letter_counts.begin(), letter_counts.end(), + [](auto const& l, auto const& r) { return l.second < r.second; }); + std::cout << "Min: " << min->first << " -> " << min->second << '\n'; + std::cout << "Max: " << max->first << " -> " << max->second << '\n'; + std::cout << "Difference: " << max->second - min->second << '\n'; + return 0; +}