From 3be0ed47c3b3f0ed6eb1c8d939c6e43620b7622c Mon Sep 17 00:00:00 2001 From: yut23 Date: Wed, 25 Dec 2024 22:30:49 -0500 Subject: [PATCH] 2024 day 24: solve part 1 --- 2024/answer_tests/day24/example1.txt | 2 + 2024/answer_tests/day24/example2.txt | 2 + 2024/input/day24/example1.txt | 10 ++ 2024/input/day24/example2.txt | 47 ++++++++ 2024/src/day24.cpp | 22 ++++ 2024/src/day24.hpp | 167 +++++++++++++++++++++++++++ 6 files changed, 250 insertions(+) create mode 100644 2024/answer_tests/day24/example1.txt create mode 100644 2024/answer_tests/day24/example2.txt create mode 100644 2024/input/day24/example1.txt create mode 100644 2024/input/day24/example2.txt create mode 100644 2024/src/day24.cpp create mode 100644 2024/src/day24.hpp diff --git a/2024/answer_tests/day24/example1.txt b/2024/answer_tests/day24/example1.txt new file mode 100644 index 0000000..ab2be7f --- /dev/null +++ b/2024/answer_tests/day24/example1.txt @@ -0,0 +1,2 @@ +Day 24: +4 diff --git a/2024/answer_tests/day24/example2.txt b/2024/answer_tests/day24/example2.txt new file mode 100644 index 0000000..594abc8 --- /dev/null +++ b/2024/answer_tests/day24/example2.txt @@ -0,0 +1,2 @@ +Day 24: +2024 diff --git a/2024/input/day24/example1.txt b/2024/input/day24/example1.txt new file mode 100644 index 0000000..8e277c1 --- /dev/null +++ b/2024/input/day24/example1.txt @@ -0,0 +1,10 @@ +x00: 1 +x01: 1 +x02: 1 +y00: 0 +y01: 1 +y02: 0 + +x00 AND y00 -> z00 +x01 XOR y01 -> z01 +x02 OR y02 -> z02 diff --git a/2024/input/day24/example2.txt b/2024/input/day24/example2.txt new file mode 100644 index 0000000..94b6eed --- /dev/null +++ b/2024/input/day24/example2.txt @@ -0,0 +1,47 @@ +x00: 1 +x01: 0 +x02: 1 +x03: 1 +x04: 0 +y00: 1 +y01: 1 +y02: 1 +y03: 1 +y04: 1 + +ntg XOR fgs -> mjb +y02 OR x01 -> tnw +kwq OR kpj -> z05 +x00 OR x03 -> fst +tgd XOR rvg -> z01 +vdt OR tnw -> bfw +bfw AND frj -> z10 +ffh OR nrd -> bqk +y00 AND y03 -> djm +y03 OR y00 -> psh +bqk OR frj -> z08 +tnw OR fst -> frj +gnj AND tgd -> z11 +bfw XOR mjb -> z00 +x03 OR x00 -> vdt +gnj AND wpb -> z02 +x04 AND y00 -> kjc +djm OR pbm -> qhw +nrd AND vdt -> hwm +kjc AND fst -> rvg +y04 OR y02 -> fgs +y01 AND x02 -> pbm +ntg OR kjc -> kwq +psh XOR fgs -> tgd +qhw XOR tgd -> z09 +pbm OR djm -> kpj +x03 XOR y03 -> ffh +x00 XOR y04 -> ntg +bfw OR bqk -> z06 +nrd XOR fgs -> wpb +frj XOR qhw -> z04 +bqk OR frj -> z07 +y03 OR x01 -> nrd +hwm AND bqk -> z03 +tgd XOR rvg -> z12 +tnw OR pbm -> gnj diff --git a/2024/src/day24.cpp b/2024/src/day24.cpp new file mode 100644 index 0000000..35c084e --- /dev/null +++ b/2024/src/day24.cpp @@ -0,0 +1,22 @@ +/****************************************************************************** + * File: day24.cpp + * + * Author: Eric T. Johnson (yut23) + * Created: 2024-12-25 + *****************************************************************************/ + +#include "day24.hpp" +#include "lib.hpp" +#include // for ifstream +#include // for cout + +int main(int argc, char **argv) { + std::ifstream infile = aoc::parse_args(argc, argv).infile; + + auto sim = aoc::day24::LogicSim::read(infile); + sim.evaluate(); + + std::cout << sim.z_value() << "\n"; + + return 0; +} diff --git a/2024/src/day24.hpp b/2024/src/day24.hpp new file mode 100644 index 0000000..eac358b --- /dev/null +++ b/2024/src/day24.hpp @@ -0,0 +1,167 @@ +/****************************************************************************** + * File: day24.hpp + * + * Author: Eric T. Johnson (yut23) + * Created: 2024-12-25 + *****************************************************************************/ + +#ifndef DAY24_HPP_SZBNX4LR +#define DAY24_HPP_SZBNX4LR + +#include "graph_traversal.hpp" // for topo_sort +#include "lib.hpp" // for skip, DEBUG, FAST +#include "unit_test/pretty_print.hpp" // for repr + +#include // for assert +#include // for size_t +#include // for istream +#include // for string, getline, to_string +#include // for unordered_map +#include // for unordered_set +#include // for move + +namespace aoc::day24 { + +enum class GateOp { AND, OR, XOR }; + +struct Gate { + std::string output; + std::string input_1; + std::string input_2; + GateOp op; +}; + +std::istream &operator>>(std::istream &is, Gate &gate) { + std::string tmp; + is >> gate.input_1 >> tmp >> gate.input_2 >> aoc::skip(1) >> gate.output; + if (tmp == "AND") { + gate.op = GateOp::AND; + } else if (tmp == "OR") { + gate.op = GateOp::OR; + } else if (tmp == "XOR") { + gate.op = GateOp::XOR; + } else if (is) { + assert(false); + } + return is; +} + +class LogicSim { + std::unordered_map values; + std::vector gates; + /// mapping from a gate's output to the corresponding index for that gate + std::unordered_map gate_lookup; + /// mapping from a gate's output to gates that use it as an input + std::unordered_map> + connections; + + void add_gate(Gate &&gate); + bool eval_gate(const std::string &key) const; + + public: + void evaluate(); + unsigned long z_value() const; + static LogicSim read(std::istream &); +}; + +void LogicSim::add_gate(Gate &&gate) { + gate_lookup.try_emplace(gate.output, gates.size()); + connections[gate.input_1].insert(gate.output); + connections[gate.input_2].insert(gate.output); + gates.push_back(std::move(gate)); +} + +bool LogicSim::eval_gate(const std::string &key) const { + if constexpr (!aoc::FAST) { + assert(!values.contains(key)); + } + const Gate &gate = gates[gate_lookup.at(key)]; + bool input_0 = values.at(gate.input_1); + bool input_1 = values.at(gate.input_2); + switch (gate.op) { + case GateOp::AND: + return input_0 && input_1; + case GateOp::OR: + return input_0 || input_1; + case GateOp::XOR: + return input_0 != input_1; + } + assert(false); +} + +void LogicSim::evaluate() { + const auto process_neighbors = [this](const std::string &key, + auto &&process) { + if (key.empty()) { + // source placeholder, process all nodes that have an initial value + for (const auto &[u, _] : values) { + process(u); + } + } + if (auto it = connections.find(key); it != connections.end()) { + for (const std::string &id : it->second) { + process(gates[gate_lookup.at(id)].output); + } + } + }; + + const std::string source = ""; + std::vector eval_order = + aoc::graph::topo_sort(source, process_neighbors); + if constexpr (aoc::DEBUG) { + std::cerr << "eval_order: " << pretty_print::repr(eval_order) << "\n"; + } + + for (const auto &key : eval_order) { + if (key.empty() || values.contains(key)) { + continue; + } + values[key] = eval_gate(key); + } + if constexpr (aoc::DEBUG) { + std::cerr << "values: " << pretty_print::repr(values) << "\n"; + } +} + +unsigned long LogicSim::z_value() const { + unsigned long z = 0; + for (int i = 0; true; ++i) { + std::string key = "z"; + if (i < 10) { + key += '0'; + } + key += std::to_string(i); + if (auto it = values.find(key); it != values.end()) { + if constexpr (aoc::DEBUG) { + std::cerr << "value for " << key << ": " << it->second << "\n"; + } + if (it->second) { + z |= 1ul << i; + } + } else { + break; + } + } + return z; +} + +LogicSim LogicSim::read(std::istream &is) { + std::string line; + LogicSim sim; + while (std::getline(is, line)) { + if (line.empty()) { + break; + } + sim.values[line.substr(0, 3)] = line[5] == '1'; + } + + Gate gate{}; + while (is >> gate) { + sim.add_gate(std::move(gate)); + } + return sim; +} + +} // namespace aoc::day24 + +#endif /* end of include guard: DAY24_HPP_SZBNX4LR */