2024-12-28 11:17:46 -08:00
|
|
|
#include <aocpp/Parsing.hpp>
|
|
|
|
#include <aocpp/Startup.hpp>
|
|
|
|
|
2024-12-28 13:24:25 -08:00
|
|
|
#include <boost/fusion/adapted/std_tuple.hpp>
|
2024-12-28 11:17:46 -08:00
|
|
|
#include <boost/spirit/include/qi.hpp>
|
|
|
|
|
|
|
|
#include <optional>
|
|
|
|
#include <stack>
|
2024-12-28 13:24:25 -08:00
|
|
|
#include <tuple>
|
2024-12-28 11:17:46 -08:00
|
|
|
|
|
|
|
namespace qi = boost::spirit::qi;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2024-12-28 12:25:56 -08:00
|
|
|
auto drop_suffix(std::uint64_t x, std::uint64_t y) -> std::optional<std::uint64_t>
|
2024-12-28 11:17:46 -08:00
|
|
|
{
|
2024-12-28 12:24:10 -08:00
|
|
|
while (x > 0) {
|
2024-12-28 11:17:46 -08:00
|
|
|
if (y == 0) { return x; }
|
2024-12-28 12:24:10 -08:00
|
|
|
if (x % 10 != y % 10) return std::nullopt;
|
2024-12-28 11:17:46 -08:00
|
|
|
x /= 10;
|
|
|
|
y /= 10;
|
|
|
|
}
|
2024-12-28 12:00:33 -08:00
|
|
|
return std::nullopt;
|
2024-12-28 11:17:46 -08:00
|
|
|
}
|
|
|
|
|
2024-12-28 13:24:25 -08:00
|
|
|
auto calibrated(
|
|
|
|
bool const part2,
|
|
|
|
std::uint64_t const target,
|
|
|
|
std::vector<std::uint64_t> const& numbers
|
|
|
|
) -> bool
|
2024-12-28 11:17:46 -08:00
|
|
|
{
|
2024-12-28 12:00:33 -08:00
|
|
|
if (numbers.size() == 0) { return false; }
|
2024-12-28 11:17:46 -08:00
|
|
|
|
2024-12-28 13:24:25 -08:00
|
|
|
auto work = std::stack<std::tuple<std::size_t, std::uint64_t>>{};
|
2024-12-28 12:00:33 -08:00
|
|
|
work.emplace(numbers.size() - 1, target);
|
|
|
|
|
|
|
|
while (not work.empty())
|
|
|
|
{
|
|
|
|
auto const [i, t] = work.top();
|
2024-12-28 11:17:46 -08:00
|
|
|
work.pop();
|
2024-12-28 12:00:33 -08:00
|
|
|
auto const x = numbers[i];
|
2024-12-28 11:17:46 -08:00
|
|
|
if (i == 0) {
|
2024-12-28 12:00:33 -08:00
|
|
|
if (x == t) { return true; }
|
2024-12-28 11:17:46 -08:00
|
|
|
} else {
|
2024-12-28 12:00:33 -08:00
|
|
|
if (x < t) { work.emplace(i - 1, t - x); }
|
|
|
|
if (t % x == 0) { work.emplace(i - 1, t / x); }
|
|
|
|
if (part2) {
|
2024-12-28 12:25:56 -08:00
|
|
|
if (auto const u = drop_suffix(t, x)) {
|
2024-12-28 12:00:33 -08:00
|
|
|
work.emplace(i - 1, *u);
|
|
|
|
}
|
|
|
|
}
|
2024-12-28 11:17:46 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
auto Main(std::istream & in, std::ostream & out) -> void
|
2024-12-28 12:24:10 -08:00
|
|
|
{
|
|
|
|
auto const input =
|
|
|
|
aocpp::ParseSimple
|
2024-12-28 13:24:25 -08:00
|
|
|
<std::vector<std::tuple<std::uint64_t, std::vector<std::uint64_t>>>>
|
|
|
|
(in, *(qi::ulong_long >> ':' >> +(' ' >> qi::ulong_long) >> '\n'));
|
2024-12-28 12:24:10 -08:00
|
|
|
|
2024-12-28 12:25:56 -08:00
|
|
|
std::uint64_t p1 = 0, p2 = 0;
|
2024-12-28 11:17:46 -08:00
|
|
|
for (auto && [x, xs] : input) {
|
2024-12-28 12:25:56 -08:00
|
|
|
if (calibrated(false, x, xs)) p1 += x;
|
|
|
|
if (calibrated(true, x, xs)) p2 += x;
|
2024-12-28 11:17:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
out << "Part 1: " << p1 << "\n"
|
|
|
|
<< "Part 2: " << p2 << "\n";
|
|
|
|
}
|