Advent of Code 2025, done in C++
at main 155 lines 4.1 kB view raw
1#include "common/getinputpath.h" 2#include <algorithm> 3#include <filesystem> 4#include <fstream> 5#include <print> 6#include <ranges> 7#include <sstream> 8#include <string> 9#include <vector> 10 11class Range { 12public: 13 Range(long long from, long long to, bool inclusive) 14 : from(from), to(to), inclusive(inclusive) {} 15 16 long long from; 17 long long to; 18 bool inclusive; 19 20 bool contains(long long value) { 21 auto real_from = std::min(from, to); 22 auto real_to = std::max(from, to); 23 24 if (inclusive) { 25 return value >= real_from && value <= real_to; 26 } else { 27 return value >= real_from && value < real_to; 28 } 29 } 30 31 long long size() { 32 auto real_from = std::min(from, to); 33 auto real_to = std::max(from, to); 34 if (inclusive) { 35 real_to += 1; 36 } 37 38 // TODO(fix): may be buggy with from is negative and to is positive 39 return real_to - real_from; 40 } 41}; 42 43// runtime on Ryzen 5 5600G: 0.003s 44int main() { 45 auto path = get_input_path(DATA_FOLDER); 46 auto data_size = std::filesystem::file_size(path); 47 std::string data = ""; 48 data.resize(data_size); 49 std::ifstream data_ifstream(path); 50 if (!data_ifstream.is_open()) { 51 std::println("Unable to read from the solution file at {}", path.string()); 52 return 1; 53 } 54 data_ifstream.read(data.data(), data_size); 55 56 auto split_idx = data.find("\n\n"); 57 auto data_ranges = data.substr(0, split_idx); 58 auto data_ids = data.substr(split_idx + 2); 59 60 std::vector<Range> ranges{}; 61 { 62 auto stream = std::stringstream(data_ranges); 63 for (std::string t; std::getline(stream, t);) { 64 // parsing 65 auto split_idx = t.find("-"); 66 auto left = std::stoll(t.substr(0, split_idx)); 67 auto right = std::stoll(t.substr(split_idx + 1)); 68 69 // RAM is expensive these days 70 // burning the CPU in attempts to occupy as less RAM at peak as possible 71 // fuck OpenAI 72 bool skip = false; 73 for (auto [i, range] : std::ranges::views::enumerate(ranges)) { 74 bool left_in_range = left >= range.from && left <= range.to; 75 bool right_in_range = right >= range.from && right <= range.to; 76 if (left_in_range && right_in_range) { 77 // my hand just itches to use goto 78 skip = true; 79 break; 80 } 81 if (left_in_range) { 82 ranges[i] = Range(range.from, right, true); 83 skip = true; 84 break; 85 } 86 if (right_in_range) { 87 ranges[i] = Range(left, range.to, true); 88 skip = true; 89 break; 90 } 91 if (left <= range.from && right >= range.to) { 92 ranges[i] = Range(left, right, true); 93 skip = true; 94 break; 95 } 96 } 97 if (skip) { 98 continue; 99 } 100 101 auto new_range = Range(left, right, true); 102 ranges.push_back(new_range); 103 } 104 } 105 106 std::sort(ranges.begin(), ranges.end(), 107 [](Range one, Range other) { return one.from < other.from; }); 108 109 std::vector<Range> merged_ranges = std::ranges::fold_left( 110 ranges, std::vector<Range>(), [](std::vector<Range> acc, Range range) { 111 if (acc.empty() || acc.back().to < range.from) { 112 acc.push_back(range); 113 } else { 114 acc.back().to = std::max(range.to, acc.back().to); 115 } 116 117 return acc; 118 }); 119 120 std::vector<long long> ids{}; 121 { 122 auto stream = std::stringstream(data_ids); 123 for (std::string t; std::getline(stream, t);) { 124 auto id = std::stoll(t); 125 ids.push_back(id); 126 } 127 } 128 129 long long password_part_1 = 0; 130 131 std::ranges::for_each(ids, [&merged_ranges, &password_part_1](long long id) { 132 bool is_fresh = false; // guilty until proven innocent! 133 for (auto range : merged_ranges) { 134 is_fresh = range.contains(id); 135 if (is_fresh) { 136 break; 137 } 138 } 139 if (is_fresh) { 140 password_part_1 += 1; 141 } 142 }); 143 144 long long password_part_2 = 0; 145 146 for (auto range : merged_ranges) { 147 password_part_2 += range.size(); 148 149 std::println("{} - {}", range.from, range.to); 150 } 151 152 std::println("Eureka! {} / {}", password_part_1, password_part_2); 153 154 return 0; 155}