Advent of Code 2025, done in C++

day[02]: solution for Part 1 and Part 2

further work on scaffolding

bpavuk.neocities.org 2eb1d0b7 eaa67bde

verified
+1
data/02/input.txt
··· 1 + 503950-597501,73731-100184,79705998-79873916,2927-3723,35155-50130,52-82,1139-1671,4338572-4506716,1991-2782,1314489-1387708,8810810-8984381,762581-829383,214957-358445,9947038-10058264,4848455367-4848568745,615004-637022,5827946-5911222,840544-1026063,19-46,372804-419902,486-681,815-1117,3928-5400,28219352-28336512,6200009-6404247,174-261,151131150-151188124,19323-26217,429923-458519,5151467682-5151580012,9354640427-9354772901,262-475,100251-151187,5407-9794,8484808500-8484902312,86-129,2-18
+1
data/02/test.txt
··· 1 + 11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124
+98
src/02/solution.cxx
··· 1 + #include "common/getinputpath.h" 2 + #include <algorithm> 3 + #include <filesystem> 4 + #include <format> 5 + #include <fstream> 6 + #include <functional> 7 + #include <print> 8 + #include <ranges> 9 + #include <regex> 10 + #include <string> 11 + 12 + #ifndef DATA_FOLDER 13 + #error \ 14 + "Meson must have defined the DATA_FOLDER somewhere in build scripts. Go check it." 15 + #endif // !DATA_FOLDER 16 + 17 + const std::filesystem::path input_path = get_input_path(DATA_FOLDER); 18 + constexpr const char delimiter = ','; 19 + 20 + struct NumberProfile { 21 + long number; 22 + bool part1_valid; 23 + bool part2_valid; 24 + }; 25 + 26 + NumberProfile is_valid(long id) { 27 + std::string id_string = std::to_string(id); 28 + 29 + bool part1_valid = true; 30 + bool part2_valid = true; 31 + 32 + for (unsigned long i = 1; i <= id_string.length(); ++i) { 33 + auto substring = id_string.substr(0, i); 34 + auto regex_str_part_1 = std::format("({}){{2}}", substring); 35 + auto regex_str_part_2 = std::format("({}){{2,}}", substring); 36 + auto regex_part_1 = std::regex(regex_str_part_1); 37 + auto regex_part_2 = std::regex(regex_str_part_2); 38 + if (part1_valid) { 39 + part1_valid = !std::regex_match(id_string, regex_part_1); 40 + } 41 + if (part2_valid) { 42 + part2_valid = !std::regex_match(id_string, regex_part_2); 43 + } 44 + if (!part1_valid && !part2_valid) { 45 + break; 46 + } 47 + } 48 + 49 + return NumberProfile{ 50 + .number = id, 51 + .part1_valid = part1_valid, 52 + .part2_valid = part2_valid, 53 + }; 54 + } 55 + 56 + // Ryzen 5 5600G runtime: 25m51s 57 + int main() { 58 + std::ifstream input(input_path); 59 + if (!input.is_open()) { 60 + std::println("Something wrong happened. Can't open file {}", 61 + input_path.string()); 62 + return 1; 63 + } 64 + 65 + unsigned long long password_part_1 = 0; 66 + unsigned long long password_part_2 = 0; 67 + 68 + // loop hell incoming 69 + for (std::string t = ""; std::getline(input, t, delimiter);) { 70 + std::println("Checking range {}", t); 71 + auto left = t.substr(0, t.find('-')); 72 + auto right = t.substr(t.find('-') + 1); 73 + 74 + auto ids = std::ranges::views::iota(std::stol(left), std::stol(right) + 1) | 75 + std::ranges::views::transform(is_valid); 76 + auto invalid_ids_part1 = 77 + ids | std::ranges::views::filter([](NumberProfile i) { 78 + return !i.part1_valid; 79 + }) | 80 + std::ranges::views::transform([](NumberProfile i) { return i.number; }); 81 + 82 + auto invalid_ids_part2 = 83 + ids | std::ranges::views::filter([](NumberProfile i) { 84 + return !i.part2_valid; 85 + }) | 86 + std::ranges::views::transform([](NumberProfile i) { return i.number; }); 87 + 88 + auto sum_part1 = std::ranges::fold_left(invalid_ids_part1, 0, std::plus{}); 89 + password_part_1 += sum_part1; 90 + 91 + auto sum_part2 = std::ranges::fold_left(invalid_ids_part2, 0, std::plus{}); 92 + password_part_2 += sum_part2; 93 + } 94 + 95 + std::println("Eureka! {} / {}", password_part_1, password_part_2); 96 + 97 + return 0; 98 + }
+9
src/common/getinputpath.cxx
··· 1 + #include "common/istest.h" 2 + #include <filesystem> 3 + 4 + const std::filesystem::path get_input_path(std::filesystem::path data_root) { 5 + std::filesystem::path data_path = 6 + data_root / (is_test() ? "test.txt" : "input.txt"); 7 + 8 + return data_path; 9 + }
+3
src/common/getinputpath.h
··· 1 + #include <filesystem> 2 + 3 + const std::filesystem::path get_input_path(std::filesystem::path data_root);
+1 -1
src/meson.build
··· 1 1 common_inc = include_directories('common') 2 2 common_lib = static_library( 3 3 'aoc_common', 4 - sources: files('common/istest.cxx'), 4 + sources: files('common/istest.cxx', 'common/getinputpath.cxx'), 5 5 include_directories: common_inc, 6 6 ) 7 7