#include "common/aoc.h" namespace y2015::day19 { struct Input { std::multimap conversions; std::string molecule; }; REGISTER_DAY(2015, Day19, Input, int); REGISTER_TEST_EXAMPLE(2015, Day19, ExampleInput, 1, 7); REGISTER_TEST(2015, Day19, Input, 1, 576); // REGISTER_TEST_EXAMPLE(2015, Day19, ExampleInput, 2, 6); REGISTER_TEST(2015, Day19, Input, 2, 207); READ_INPUT(input) { Input i; std::string str; while (getline(input, str)) { if (str.empty()) break; std::string from; std::string to; std::stringstream ss{str}; ss >> from >> "=>" >> to; i.conversions.emplace(from, to); } getline(input, i.molecule); return i; } std::vector FindAll(const std::string& str, const std::string& find) { std::vector positions; size_t pos = str.find(find); while (pos != std::string::npos) { positions.emplace_back(pos); pos = str.find(find, pos + 1); } return positions; } bool IsAtom(const std::string& sv) { std::regex regex{"^(e|[A-Z][a-z]?)$"}; return std::regex_match(sv, regex); } std::string Prettify(const std::string& molecule) { std::string result = molecule; for (size_t i = 0; i < result.size(); i++) { if (Helper::StartsWith(result, "Rn", i)) { result.replace(i, 2, "("); i--; } else if (Helper::StartsWith(result, "Ar", i)) { result.replace(i, 2, ")"); i--; } else if (Helper::StartsWith(result, "Y", i)) { result.replace(i, 1, ","); } } return result; } std::pair Solve(const std::string& molecule, const std::multimap& conversions, std::map>& memoization); void Solve(std::string& molecule, int& steps, size_t& offset, size_t pos, size_t size, const std::multimap& conversions, std::map>& memoization) { std::string toReduce = molecule.substr(pos, size); auto [solveStr, solveSteps] = Solve(toReduce, conversions, memoization); Helper::Replace(molecule, toReduce.size(), solveStr, pos); steps += solveSteps; offset -= toReduce.size() - solveStr.size(); } void SolveRnAr(std::string& molecule, int& steps, const std::multimap& conversions, std::map>& memoization) { // Solve all parts between Rn and Ar int stack = 0; size_t position = 0; for (size_t i = 0; i < molecule.size(); i++) { if (Helper::StartsWith(molecule, "Rn", i)) { if (stack == 0) position = i + 2; i++; stack++; } else if (Helper::StartsWith(molecule, "Ar", i)) { stack--; if (stack == 0) { Solve(molecule, steps, i, position, i - position, conversions, memoization); } i++; } } } bool SolveY(std::string& molecule, int& steps, const std::multimap& conversions, std::map>& memoization) { // Reduce all parts split by Y int stack = 0; size_t position = 0; bool hasY = false; for (size_t i = 0; i < molecule.size(); i++) { if (Helper::StartsWith(molecule, "Rn", i)) stack++; else if (Helper::StartsWith(molecule, "Ar", i)) stack--; if (Helper::StartsWith(molecule, "Y", i)) { if (stack != 0) continue; hasY = true; Solve(molecule, steps, i, position, i - position, conversions, memoization); position = i + 1; } } if (hasY) { size_t i = 0; Solve(molecule, steps, i, position, molecule.size(), conversions, memoization); return true; } return false; } void SolveAr(std::string& molecule, int& steps, const std::multimap& conversions, std::map>& memoization) { // Reduce all parts ending with Ar (except the last one) for (size_t i = 0; i < molecule.size(); i++) { if (Helper::StartsWith(molecule, "Ar", i) && i != molecule.size() - 2) { Solve(molecule, steps, i, 0, i + 2, conversions, memoization); } } } std::pair SolveToAtom(const std::string& molecule, const std::multimap& conversions, std::map>& memoization) { if (IsAtom(molecule)) return {molecule, 0}; auto it = memoization.find(molecule); if (it != memoization.end()) return it->second; int steps = std::numeric_limits::max(); std::string result = "."; for (const auto& [from, to] : conversions) { std::vector positions = FindAll(molecule, from); for (const auto& pos : positions) { std::string moleculeCpy = molecule; moleculeCpy.replace(pos, from.size(), to); auto [solveStr, solveSteps] = SolveToAtom(moleculeCpy, conversions, memoization); if (solveStr == ".") continue; if (solveSteps < steps) { steps = solveSteps; result = solveStr; } } } memoization[molecule] = {result, steps + 1}; return {result, steps + 1}; } void SolveToAtom(std::string& molecule, int& steps, const std::multimap& conversions, std::map>& memoization) { // Reduce the rest auto [solveStr, solveSteps] = SolveToAtom(molecule, conversions, memoization); if (solveStr == ".") { std::cout << "No solution found for: " << molecule << std::endl; } Helper::Replace(molecule, molecule.size(), solveStr, 0); steps += solveSteps; } std::pair Solve(const std::string& molecule, const std::multimap& conversions, std::map>& memoization) { if (IsAtom(molecule)) return {molecule, 0}; std::string result = molecule; int steps = 0; SolveRnAr(result, steps, conversions, memoization); if (SolveY(result, steps, conversions, memoization)) return {result, steps}; SolveAr(result, steps, conversions, memoization); SolveToAtom(result, steps, conversions, memoization); return {result, steps}; } OUTPUT1(input) { std::set uniques; for (const auto& [from, to] : input.conversions) { std::vector positions = FindAll(input.molecule, from); for (const auto& pos : positions) { std::string str = input.molecule; Helper::Replace(str, from.size(), to, pos); uniques.emplace(str); } } return uniques.size(); } OUTPUT2(input) { std::multimap reverse; for (const auto& [from, to] : input.conversions) { reverse.emplace(to, from); } std::map> memoization; return Solve(input.molecule, reverse, memoization).second; } }