#include #include #include #include #include #include #include #include #include #include namespace { struct Monkey { std::vector items; std::int64_t divisor; std::size_t true_ix, false_ix; std::optional rhs; char op; }; auto Parse(std::istream & in) -> std::vector { std::string word; std::vector monkies; while (in >> word) { monkies.emplace_back(); Monkey & m = monkies.back(); in >> word >> word >> word; // 0: Starting items: for (;;) { std::int64_t elt; in >> elt; m.items.push_back(elt); char c; in >> c; if (c != ',') break; } in >> word >> word >> word >> word; // Operation: new = old in >> m.op >> word; if (word != "old") m.rhs = std::stoll(word); in >> word >> word >> word >> m.divisor; in >> word >> word >> word >> word >> word >> m.true_ix >> word >> word >> word >> word >> word >> m.false_ix; } return monkies; } auto Solve(std::vector const& input, std::size_t const rounds, std::optional const modulus) -> std::int64_t { std::vector throws(input.size()); for (auto const i : boost::irange(input.size())) { for (auto item : input[i].items) { auto cursor = i; for (auto n = rounds; n > 0;) { throws[cursor]++; auto const& m = input[cursor]; auto const y = m.rhs.value_or(item); switch (m.op) { case '+': item += y; break; case '*': item *= y; break; default: throw std::runtime_error{"bad input"}; } if (modulus.has_value()) { item %= *modulus; } else { item /= 3; } auto const next = (item % m.divisor == 0) ? m.true_ix : m.false_ix; if (next < cursor) n--; cursor = next; } } } // Compute top 2 elements of the vector std::partial_sort(throws.begin(), throws.begin()+2, throws.end(), std::greater()); return throws[0] * throws[1]; } auto Part1(std::vector const& input) -> std::int64_t { return Solve(input, 20, {}); } auto Part2(std::vector const& input) -> std::int64_t { auto const modulus = std::transform_reduce( input.cbegin(), input.cend(), std::int64_t{1}, std::lcm, [](Monkey const& m) { return m.divisor; }); return Solve(input, 10'000, modulus); } } // namespace TEST_SUITE("2022-11 examples") { TEST_CASE("example") { std::istringstream in { R"(Monkey 0: Starting items: 79, 98 Operation: new = old * 19 Test: divisible by 23 If true: throw to monkey 2 If false: throw to monkey 3 Monkey 1: Starting items: 54, 65, 75, 74 Operation: new = old + 6 Test: divisible by 19 If true: throw to monkey 2 If false: throw to monkey 0 Monkey 2: Starting items: 79, 60, 97 Operation: new = old * old Test: divisible by 13 If true: throw to monkey 1 If false: throw to monkey 3 Monkey 3: Starting items: 74 Operation: new = old + 3 Test: divisible by 17 If true: throw to monkey 0 If false: throw to monkey 1 )" }; auto const input = Parse(in); CHECK(Part1(input) == 10605); CHECK(Part2(input) == 2713310158); } } auto Main(std::istream & in, std::ostream & out) -> void { auto const input {Parse(in)}; out << "Part 1: " << Part1(input) << std::endl; out << "Part 2: " << Part2(input) << std::endl; }