#include #include #include #include #include #include #include #include #include #include #include enum class Level { low, high }; using UInt = std::uint64_t; using Signal = std::tuple; using Signals = std::list; using StringVector = std::vector; constexpr bool debug = false; struct Node { virtual ~Node() = 0; virtual void add_input(std::string const& node) = 0; void add_output(std::string const& node) { dests_.push_back(node); } void receive(std::back_insert_iterator it, Signal const& signal) { auto out{output_level(signal)}; if (!out) { return; } for (auto const& dest : dests_) { *it++ = std::make_tuple(std::get<1>(signal), dest, *out); } } private: virtual auto output_level(Signal const& signal) noexcept -> std::optional = 0; StringVector dests_; }; Node::~Node() = default; struct ButtonNode final : public Node { ~ButtonNode() override = default; void add_input(const std::string& node) override { std::abort(); } private: auto output_level(const Signal& signal) noexcept -> std::optional override { return Level::low; } }; struct BroadcasterNode final : public Node { ~BroadcasterNode() override = default; void add_input([[maybe_unused]] const std::string& node) override { } private: auto output_level(const Signal& signal) noexcept -> std::optional override { return std::get<2>(signal); } }; struct FlipFlopNode final : public Node { ~FlipFlopNode() override = default; void add_input(const std::string& node) override { } private: auto output_level(const Signal& signal) noexcept -> std::optional override { if (std::get<2>(signal) == Level::high) { return std::nullopt; } output_ = (output_ == Level::low) ? Level::high : Level::low; return output_; } Level output_{Level::low}; }; struct ConjunctionNode final : public Node { ~ConjunctionNode() override = default; void add_input(const std::string& node) override { inputs_.insert({node, Level::low}); } private: auto output_level(const Signal& signal) noexcept -> std::optional override { auto it = inputs_.find(std::get<0>(signal)); assert(it != inputs_.end()); it->second = std::get<2>(signal); Level output = Level::low; for (auto const& input : inputs_) { if (input.second == Level::low) { output = Level::high; break; } } return output; } std::unordered_map inputs_; }; struct NodeMap { NodeMap(StringVector rows) { auto button = new ButtonNode(); button->add_output("broadcaster"); nodes_.insert({"button", button}); for (auto const& row : rows) { auto pos = 0; Node* node = make_node(row[0]); if (row[pos] == '%' || row[pos] == '&') { ++pos; } auto const name_start = pos; auto const name_end = row.find(' ', pos); auto [it, success] = nodes_.insert({row.substr(name_start, name_end - name_start), node}); assert(success); } for (auto const& row : rows) { auto pos = (row[0] == '%' || row[0] == '&') ? 1 : 0; auto const from_start = pos; auto const from_end = row.find(' ', pos); assert(row.substr(from_end, 4) == " -> "); pos = from_end + 2; auto from = row.substr(from_start, from_end - from_start); auto const from_it = nodes_.find(from); assert(from_it != nodes_.end()); while (pos < row.size()) { pos += 2; auto const to_start = pos; auto to_end = row.find(',', pos); if (to_end == std::string::npos) { to_end = row.size(); } auto to = row.substr(to_start, to_end - to_start); pos = to_end; from_it->second->add_output(to); auto const to_it = nodes_.find(to); if (to_it != nodes_.end()) { to_it->second->add_input(from); } } } } [[nodiscard]] auto press_button() -> bool { ++button_count_; Signals work_list; work_list.emplace_back("button", "broadcaster", Level::low); bool done{false}; auto inserter{std::back_inserter(work_list)}; while (!work_list.empty()) { auto [from, to, level] = work_list.front(); work_list.pop_front(); if (to == "ns" && level == Level::high) { std::cout << from << " -high: " << to << ": " << button_count_ << '\n'; } if (to == "rx" && level == Level::low) { done = true; } auto const it = nodes_.find(to); if constexpr (debug) { std::cout << from << " -" << (level == Level::low ? "low" : "high") << ": " << to << '\n'; } if (it != nodes_.end()) { it->second->receive(inserter, std::make_tuple(from, to, level)); } } return done; } ~NodeMap() { for (auto const& node : nodes_) { delete node.second; } } private: [[nodiscard]] static auto make_node(char const c) -> Node* { switch (c) { case '%': return new FlipFlopNode; case '&': return new ConjunctionNode; default: return new BroadcasterNode; } } std::unordered_map nodes_; UInt button_count_{0}; }; auto main() -> int try { std::string line; StringVector lines; while (std::getline(std::cin, line)) { lines.push_back(line); } NodeMap nodes(lines); bool done{false}; UInt loop_count{0}; while (!done) { ++loop_count; done = nodes.press_button(); } std::cout << "Loop count: " << loop_count << '\n'; return EXIT_SUCCESS; } catch (...) { std::cerr << "Uncaught exception.\n"; return EXIT_FAILURE; }