#include #include #include #include #include #include #include #include #include "doctest.h" namespace day2 { const std::string sample = "11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528," "446443-446449,38593856-38593862,565653-565659,824824821-824824827," "2121212118-2121212124"; struct Range { uint64_t start; uint64_t end; }; } // namespace day2 template<> struct std::formatter : std::formatter { static auto format(const day2::Range &i, std::format_context &ctx) { return std::format_to(ctx.out(), "Range[start: {}, end: {}]", i.start,i.end); } }; namespace day2 { Range parse_range(std::string_view s) { std::string_view start; std::string_view end; for (size_t i = 0; i < s.size(); i++) { const char c = s[i]; if (c == '-') { start = {s.data(), i}; end = {s.data() + i + 1, s.size() - start.size()}; } } Range range; uint64_t parsed; std::from_chars(start.data(), start.end(), parsed); range.start = parsed; std::from_chars(end.data(), end.end(), parsed); range.end = parsed; return range; } size_t find_divisor(uint64_t n) { for (size_t i = 1;; i++) { size_t div = n / std::pow(10, i); if (div == 0) { return std::pow(10, (i / 2)); } } assert(0 && "Unreachable"); } uint64_t count_repetitions(const Range range) { uint64_t total = 0; for (uint64_t n = range.start; n <= range.end; n++) { auto div = find_divisor(n); auto left = n / div; auto right = n % div; if (left == right) total++; } return total; } uint64_t sum_repetitions(const Range range) { uint64_t total = 0; for (uint64_t n = range.start; n <= range.end; n++) { auto div = find_divisor(n); auto left = n / div; auto right = n % div; if (left == right) total += n; } return total; } uint64_t solve_first(std::string_view input) { uint64_t result = 0; for (const auto range : std::views::split(input, ',') | std::views::transform([](auto s) { return parse_range(std::string_view(s)); })) { result += sum_repetitions(range); } return result; } uint64_t sum_repetitions_2(const Range range, std::string& buf) { uint64_t total = 0; for (uint64_t n = range.start; n <= range.end; n++) { std::format_to(buf, "{}", n); } return total; } uint64_t solve_second(std::string_view input) { std::string buf; buf.reserve(100); uint64_t result = 0; for (const auto range : std::views::split(input, ',') | std::views::transform([](auto s) { return parse_range(std::string_view(s)); })) { result += sum_repetitions_2(range, buf); buf.clear(); } return result; } TEST_CASE("Can parse input") { auto range = parse_range("11-22"); CHECK(range.start == 11); CHECK(range.end == 22); } TEST_CASE("Solve first sample") { CHECK(solve_first(sample) == 1227775554); } TEST_CASE("Solve first input") { std::ifstream fs("day2input.txt"); std::stringstream ss{}; ss << fs.rdbuf(); CHECK(solve_first(ss.str()) == 1227775554); } TEST_CASE("Find divisor works") { CHECK(find_divisor(11) == 10); CHECK(find_divisor(1221) == 100); CHECK(find_divisor(222222) == 1000); } TEST_CASE("Count repetition works") { CHECK(count_repetitions({.start = 11, .end = 22}) == 2); CHECK(count_repetitions({.start = 1188511880, .end = 1188511890}) == 1); } } // namespace day2