aoc25/day2/main.cpp
2025-12-03 23:05:57 +00:00

153 lines
4.9 KiB
C++

#include <iostream>
#include <fstream>
#include <string>
#include <string_view>
#include <vector>
#include <expected>
#include <print>
#include <ranges>
#include <array>
#include <map>
#include <numeric>
#include <functional>
#include <algorithm>
struct IDRange {
long leftRange;
long rightRange;
};
auto parseRanges(const std::string& filename) -> std::expected<std::vector<IDRange>, std::string> {
std::ifstream inputF {filename};
if (!inputF){
return std::unexpected{"Some file open error.\n"};
}
std::vector<IDRange> idRanges{};
std::string bigString{};
std::getline(inputF,bigString);
auto ranges = std::ranges::to<std::vector<std::string>>(std::views::split(bigString, ','));
for(const auto& range : ranges){
auto subParts = std::ranges::to<std::vector<std::string>>(std::views::split(range, '-'));
idRanges.emplace_back(std::stol(subParts[0]), std::stol(subParts[1]));
}
inputF.close();
return std::move(idRanges);
}
auto countDoubles(const std::vector<IDRange>& idRanges) {
long doubles{};
for(const auto& rng : idRanges){
//std::println("{}-{}", rng.leftRange, rng.rightRange);
for( long i = rng.leftRange; i <= rng.rightRange; i++){
auto str_version = std::to_string(i) ;
auto str_len = str_version.size();
//std::print("Checking {}. Length: {}", str_version, str_version.size());
if (str_len % 2 == 0) {
//std::print(" Divisible by two, splitting...");
std::string_view left_half = std::string_view(str_version).substr(0, str_len/2);
std::string_view right_half = std::string_view(str_version).substr(str_len/2, str_len);
//std::print("Halves: {}/{}",left_half, right_half);
if(left_half == right_half){
//std::print(" EQUAL!");
doubles += i;
}
}
//std::println();
}
}
return doubles;
}
auto calculatePossibleSplits(int length) -> std::vector<int>{
//std::println("Possible ways to split a str of length {}: ", length);
std::vector<int> returnVec{};
for(auto toCheck : std::views::iota(2, length+1)){
if(length % toCheck == 0)
{
//std::println("{}", toCheck);
returnVec.push_back(toCheck);
}
}
return std::move(returnVec);
}
std::unordered_map<int, std::vector<int>> splitMap{};
auto getPossibleSplits(int length) -> const std::vector<int>&{
if(!splitMap.contains(length)){
//std::println("Caching {}",length);
splitMap[length] = calculatePossibleSplits(length);
}
return splitMap.at(length);
}
auto countRepeats(const std::vector<IDRange>& idRanges) {
long doubles{};
for(const auto& rng : idRanges){
//std::println("{}-{}", rng.leftRange, rng.rightRange);
for( long i = rng.leftRange; i <= rng.rightRange; i++){
auto str_version = std::to_string(i) ;
auto str_len = str_version.size();
//std::print("Checking {}. Length: {} ", str_version, str_version.size());
std::vector<int> numsToCheck = getPossibleSplits(str_len);
//std::println("Possible splits: {}", numsToCheck);
for (int checkNum : numsToCheck)
{
//std::print("Splitting in {}: ", checkNum);
std::vector<std::string_view> splits(checkNum);
for(auto toCheck : std::views::iota(0, checkNum)){
auto window = str_len/checkNum;
splits[toCheck] = std::string_view(str_version).substr(toCheck*window, window);
//std::print("[{}]: {} /{} ", toCheck, splits[toCheck], window);
}
if(std::equal(splits.begin() + 1, splits.end(), splits.begin())){
//std::print(" EQUAL!");
doubles += i;
break;
}
//std::println();
}
//std::println();
}
//std::println();
}
return doubles;
}
auto main() -> int {
auto testCase = parseRanges("test_input");
if(testCase) {
auto testResult = countDoubles(*testCase);
auto testResultP2 = countRepeats(*testCase);
std::println("P1 Testcase result: {}", testResult);
std::println("P2 Testcase result: {}", testResultP2);
}
else{
std::print("{}\n", testCase.error());
}
auto realRanges = parseRanges("puzzle_input");
if(realRanges) {
//auto realResult = countDoubles(*realRanges);
auto realResultP2 = countRepeats(*realRanges);
//std::println("P1 Real result: {}", realResult);
std::println("P2 Real result: {}", realResultP2);
}
else{
std::print("{}\n", realRanges.error());
}
return 0;
}