Day 11: Reactor
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465


C++
Dynamic programming and recursion - it’s the AoC classic. Nothing tricky here, which is a relief after yesterday.
No sign of Dijkstra’s yet, which is a surprise. Maybe it’ll be tomorrow’s puzzle? 25th is usually an open goal if you’ve done the rest of the puzzles, but I don’t know if that applies to the new shorter format.
#include <boost/log/trivial.hpp> #include <boost/unordered/unordered_flat_map.hpp> #include <boost/unordered/unordered_flat_set.hpp> #include <fstream> #include <sstream> #include <stdexcept> #include <vector> namespace { using Map = boost::unordered::unordered_flat_map<std::string, std::vector<std::string>>; auto read(const std::string &name) { auto rval = Map{}; auto ih = std::ifstream{name}; if (!ih) throw std::runtime_error{"file?"}; auto line = std::string{}; while (std::getline(ih, line)) { auto ss = std::istringstream{line}; auto tmp = std::string{}; ss >> tmp; auto key = tmp.substr(0, tmp.size() - 1); auto value = std::vector<std::string>{}; while (ss >> tmp) value.push_back(std::move(tmp)); rval[key] = std::move(value); } return rval; } auto part1() { auto map = read("11.1.txt"); auto current = std::vector<std::vector<std::string>>{}; auto paths = boost::unordered::unordered_flat_set<std::vector<std::string>>{}; current.push_back(std::vector<std::string>{"you"}); while (!current.empty()) { auto next_up = decltype(current){}; std::swap(current, next_up); for (const auto &next : next_up) { auto &outputs = map.at(next.back()); for (auto &output : outputs) { if (output == "you") continue; auto token = next; token.push_back(output); if (output == "out") { paths.insert(std::move(token)); } else { current.push_back(std::move(token)); } } } } return paths.size(); } struct Route { std::string current; bool has_fft, has_dac; }; struct RouteHash { std::size_t operator()(const Route &p) const { std::size_t seed = 0; boost::hash_combine(seed, p.current); boost::hash_combine(seed, p.has_fft); boost::hash_combine(seed, p.has_dac); return seed; } }; auto operator==(const Route &a, const Route &b) { return a.current == b.current && a.has_fft == b.has_fft && a.has_dac == b.has_dac; } auto cache = boost::unordered::unordered_flat_map<Route, size_t, RouteHash>{}; auto count_target(Route start, const Map &map) -> size_t { auto outputs = map.at(start.current); if (start.current == "dac") start.has_dac = true; if (start.current == "fft") start.has_fft = true; auto rval = size_t{}; for (auto &output : outputs) { if (auto f = cache.find({output, start.has_fft, start.has_dac}); f != cache.end()) { rval += f->second; continue; } if (output == "out") { if (start.has_dac && start.has_fft) { ++rval; } continue; } rval += count_target({output, start.has_fft, start.has_dac}, map); } cache[start] = rval; return rval; } auto part2() { auto map = read("11.2.txt"); return count_target({"svr", false, false}, map); } } // namespace auto main() -> int { BOOST_LOG_TRIVIAL(info) << "Day 11"; BOOST_LOG_TRIVIAL(info) << "1: " << part1(); BOOST_LOG_TRIVIAL(info) << "2: " << part2(); }