Advent of Code 2025, done in C++
at main 106 lines 3.1 kB view raw
1#include "common/getinputpath.h" 2#include <algorithm> 3#include <filesystem> 4#include <format> 5#include <fstream> 6#include <functional> 7#include <iterator> 8#include <print> 9#include <ranges> 10#include <regex> 11#include <string> 12#include <vector> 13 14#ifndef DATA_FOLDER 15#error \ 16 "Meson must have defined the DATA_FOLDER somewhere in build scripts. Go check it." 17#endif // !DATA_FOLDER 18 19const std::filesystem::path input_path = get_input_path(DATA_FOLDER); 20constexpr const char delimiter = ','; 21 22struct NumberProfile { 23 long number; 24 bool part1_valid; 25 bool part2_valid; 26}; 27 28[[nodiscard]] NumberProfile is_valid(long id) { 29 std::string id_string = std::to_string(id); 30 31 bool part1_valid = true; 32 bool part2_valid = true; 33 34 // repeats 2 times 35 if (id_string.length() % 2 == 0 && part1_valid) { 36 bool invalid = id_string.substr(0, id_string.length() / 2) == 37 id_string.substr(id_string.length() / 2); 38 part1_valid = !invalid; 39 } 40 41 // repeats more than 2 times 42 if (id_string.length() >= 2 && part2_valid) { 43 auto t = id_string + id_string; 44 part2_valid = 45 t.substr(1, t.length() - 2).find(id_string) == std::string::npos; 46 } 47 48 return NumberProfile{ 49 .number = id, 50 .part1_valid = part1_valid, 51 .part2_valid = part2_valid, 52 }; 53} 54 55// Ryzen 5 5600G runtime: 1s494ms 56int main() { 57 std::ifstream input(input_path); 58 if (!input.is_open()) { 59 std::println("Something wrong happened. Can't open file {}", 60 input_path.string()); 61 return 1; 62 } 63 64 unsigned long long password_part_1 = 0; 65 unsigned long long password_part_2 = 0; 66 67 // loop hell incoming 68 for (std::string t = ""; std::getline(input, t, delimiter);) { 69 std::println("Checking range {}", t); 70 auto left = t.substr(0, t.find('-')); 71 auto right = t.substr(t.find('-') + 1); 72 73 auto ids = std::vector<NumberProfile>(std::stol(right) - std::stol(left)); 74 75 { 76 auto ids_num = std::vector<long>(std::stol(right) - std::stol(left)); 77 std::ranges::iota(ids_num.begin(), ids_num.end(), std::stol(left)); 78 std::ranges::transform(ids_num, std::back_inserter(ids), 79 [](auto i) { return is_valid(i); }); 80 } 81 82 auto invalid_ids_part1 = 83 ids | std::ranges::views::filter([](NumberProfile i) { 84 return !i.part1_valid; 85 }) | 86 std::ranges::views::transform([](NumberProfile i) { return i.number; }); 87 88 auto invalid_ids_part2 = 89 ids | std::ranges::views::filter([](NumberProfile i) { 90 return !i.part2_valid; 91 }) | 92 std::ranges::views::transform([](NumberProfile i) { return i.number; }); 93 94 auto sum_part1 = 95 std::ranges::fold_left(invalid_ids_part1, 0ULL, std::plus<>{}); 96 password_part_1 += sum_part1; 97 98 auto sum_part2 = 99 std::ranges::fold_left(invalid_ids_part2, 0ULL, std::plus<>{}); 100 password_part_2 += sum_part2; 101 } 102 103 std::println("Eureka! {} / {}", password_part_1, password_part_2); 104 105 return 0; 106}