finish day 2

This commit is contained in:
2025-12-02 17:03:54 -05:00
parent 002c7f6a7e
commit 05a5bc27ad

224
day2.cpp
View File

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