Posted on: 2025-12-02, Updated on: 2025-12-03 20:39:37 | Read time: 4.4 minutes
Topic(s): programming
For an introduction to the Advent of Code, checkout my first article for AOC 2025. This article will cover my solution for the first and second parts of Day 2.
NOTE: It should go without saying that this article will contain spoilers for the given day's Advent of Code problem. Continue reading at your own risk!
// Advent of Code 2025 - Day 02 Part 1
#include "AdventOfCodeStd.hpp"
using namespace AOC;
using range_t = std::pair<std::uint64_t, std::uint64_t>; // Storage ID range [start, end]
auto main(void) -> int try
{
std::string s;
std::getline(std::cin, s);
auto rng = std::string_view(s)
| std::views::split(',')
| std::views::transform([](auto &&sub_expr) -> std::string_view
{
auto first = &*sub_expr.begin();
auto len = std::ranges::distance(sub_expr);
return std::string_view(first, static_cast<std::size_t>(len));
})
| std::views::transform([](std::string_view sv) -> range_t
{
const auto dash_idx = sv.find('-');
if (dash_idx == decltype(sv)::npos) throw std::runtime_error("AAAAHHH");
//std::println("{} {}", sv.substr(0, dash_idx), sv.substr(dash_idx + 1));
return {
std::stoull(std::string(sv.substr(0, dash_idx))),
std::stoull(std::string(sv.substr(dash_idx + 1)))
};
})
| std::ranges::to<std::vector<range_t>>(); // Convert to vec of range_t's
std::vector<std::uint64_t> invalids; // Store invalid ID's for summation
for (const auto &[first, second] : rng)
{
auto nums = std::views::iota(first, second + 1); // [first, second]
auto is_invalid = [](auto num) -> bool
{
const std::string digits = std::to_string(num);
const auto n = digits.size(), half = n / 2;
return (n % 2 == 0) && (digits.substr(0, half) == digits.substr(half));
};
// Filter the invalid ID's and put them in the invalids vec
std::ranges::copy(nums | std::views::filter(is_invalid), std::back_inserter(invalids));
}
// Sum of the invalid ID #'s is the answer:
std::println("{}", std::ranges::fold_left(invalids, std::uint64_t{0}, std::plus<>()));
}
catch (const std::exception &ex)
{
std::println("{}", ex.what());
}
The first part of my solution for Part 1 reads in the singular input line and uses std::views::split to create a sub view based on the comma delimiter. This sub view is this transformed into a std::string_view, and is sent through another transformation to parse the ID range XXXXX-XXXXX and put the numbers into a range_t (std::pair<std::uint64_t, std::uint64_t>). Finally, the view is converted to a std::vector of range_t pair objects.
With the input stored, solving the problem is as simple as filtering the invalid ID numbers and summing them. The ID number ranges are iterated through and std::views::iota is used to create a view of all the numbers in the range [start, end]. To check if an ID is invalid, I compared the first and second halves of digits in numbers with even-numbered digit counts. The rest of the code just sums the invalid ID numbers that were collected.
NOTE: Larger numeric types are needed since the input numbers for this problem are sufficiently large!
// Advent of Code 2025 - Day 02 Part 2
#include "AdventOfCodeStd.hpp"
using namespace AOC;
using range_t = std::pair<std::uint64_t, std::uint64_t>; // Storage ID range [start, end]
auto main(void) -> int try
{
std::string s;
std::getline(std::cin, s);
auto rng = std::string_view(s)
| std::views::split(',')
| std::views::transform([](auto &&sub_expr) -> std::string_view
{
auto first = &*sub_expr.begin();
auto len = std::ranges::distance(sub_expr);
return std::string_view(first, static_cast<std::size_t>(len));
})
| std::views::transform([](std::string_view sv) -> range_t
{
const auto dash_idx = sv.find('-');
if (dash_idx == decltype(sv)::npos) throw std::runtime_error("AAAAHHH");
//std::println("{} {}", sv.substr(0, dash_idx), sv.substr(dash_idx + 1));
return {
std::stoull(std::string(sv.substr(0, dash_idx))),
std::stoull(std::string(sv.substr(dash_idx + 1)))
};
})
| std::ranges::to<std::vector<range_t>>(); // Convert to vec of range_t's
std::vector<std::uint64_t> invalids; // Store invalid ID's for summation
for (const auto &[first, second] : rng)
{
auto nums = std::views::iota(first, second + 1); // [first, second]
auto is_invalid = [](auto num) -> bool
{
const std::string digits = std::to_string(num);
const auto n = digits.size(), half = n / 2;
// Never consider odd length digit strings
if (n % 2 == 0 && digits.substr(0, half) == digits.substr(half))
return true;
else
{
// std::print("For {}: ", num);
// No need to check n %2
for (std::size_t t = 1; t < n; ++t)
{
//if (n % t != 0) continue;
auto chunks = std::string_view{digits} | std::views::chunk(t);
auto ref = *chunks.begin(); // The first chunk
auto rest = chunks | std::views::drop(1); // All but the first chunk
bool all_equal = std::ranges::all_of(rest, [&ref, &rest](auto chunk)
{
return std::ranges::equal(ref, chunk);
});
if (all_equal)
{
std::print("{}, ", chunks);
std::println();
return true;
}
}
//std::println();
}
return false;
};
// Filter the invalid ID's and put them in the invalids vec
std::ranges::copy(nums | std::views::filter(is_invalid), std::back_inserter(invalids));
}
// Sum of the invalid ID #'s is the answer:
std::println("{}", std::ranges::fold_left(invalids, std::uint64_t{0}, std::plus<>()));
//std::println("\n{}\n", invalids);
}
catch (const std::exception &ex)
{
std::println("{}", ex.what());
}
The main difference between the second and first parts of today's problem is the additional condition for invalid ID numbers. Now, ID's can also be invalid if the periodic sub-sequence is repeated two or more times. I've kept the original condition from part one as:
if (n % 2 == 0 && digits.substr(0, half) == digits.substr(half))
return true;
Now the way I've accomplished the periodic sub-sequence check for any number that is two or greater is by first splitting up the sequence into chunks of size 1 <= t < n using std::views::chunk(t). Then I take the first element the chunk view and compare every other chunk to it. If they are all equal, then the is_invalid(auto num) -> bool lambda can immediately return true. All of the other code is identical.
Thanks for reading, and stay tuned for more articles about this year's Advent of Code!
Resources: