#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()); const 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; }