#include #include #include #include #include #include #include #include #include #include #include #include #include struct IDRange { long leftRange; long rightRange; }; auto parseRanges(const std::string& filename) -> std::expected, std::string> { std::ifstream inputF {filename}; if (!inputF){ return std::unexpected{"Some file open error.\n"}; } std::vector idRanges{}; std::string bigString{}; std::getline(inputF,bigString); auto ranges = std::ranges::to>(std::views::split(bigString, ',')); for(const auto& range : ranges){ auto subParts = std::ranges::to>(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& 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{ //std::println("Possible ways to split a str of length {}: ", length); std::vector 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> splitMap{}; auto getPossibleSplits(int length) -> const std::vector&{ if(!splitMap.contains(length)){ //std::println("Caching {}",length); splitMap[length] = calculatePossibleSplits(length); } return splitMap.at(length); } auto countRepeats(const std::vector& 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 numsToCheck = getPossibleSplits(str_len); //std::println("Possible splits: {}", numsToCheck); for (int checkNum : numsToCheck) { //std::print("Splitting in {}: ", checkNum); std::vector 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; }