#include "common/getinputpath.h" #include #include #include #include #include #include #include #include class Range { public: Range(long long from, long long to, bool inclusive) : from(from), to(to), inclusive(inclusive) {} long long from; long long to; bool inclusive; bool contains(long long value) { auto real_from = std::min(from, to); auto real_to = std::max(from, to); if (inclusive) { return value >= real_from && value <= real_to; } else { return value >= real_from && value < real_to; } } long long size() { auto real_from = std::min(from, to); auto real_to = std::max(from, to); if (inclusive) { real_to += 1; } // TODO(fix): may be buggy with from is negative and to is positive return real_to - real_from; } }; // runtime on Ryzen 5 5600G: 0.003s int main() { auto path = get_input_path(DATA_FOLDER); auto data_size = std::filesystem::file_size(path); std::string data = ""; data.resize(data_size); std::ifstream data_ifstream(path); if (!data_ifstream.is_open()) { std::println("Unable to read from the solution file at {}", path.string()); return 1; } data_ifstream.read(data.data(), data_size); auto split_idx = data.find("\n\n"); auto data_ranges = data.substr(0, split_idx); auto data_ids = data.substr(split_idx + 2); std::vector ranges{}; { auto stream = std::stringstream(data_ranges); for (std::string t; std::getline(stream, t);) { // parsing auto split_idx = t.find("-"); auto left = std::stoll(t.substr(0, split_idx)); auto right = std::stoll(t.substr(split_idx + 1)); // RAM is expensive these days // burning the CPU in attempts to occupy as less RAM at peak as possible // fuck OpenAI bool skip = false; for (auto [i, range] : std::ranges::views::enumerate(ranges)) { bool left_in_range = left >= range.from && left <= range.to; bool right_in_range = right >= range.from && right <= range.to; if (left_in_range && right_in_range) { // my hand just itches to use goto skip = true; break; } if (left_in_range) { ranges[i] = Range(range.from, right, true); skip = true; break; } if (right_in_range) { ranges[i] = Range(left, range.to, true); skip = true; break; } if (left <= range.from && right >= range.to) { ranges[i] = Range(left, right, true); skip = true; break; } } if (skip) { continue; } auto new_range = Range(left, right, true); ranges.push_back(new_range); } } std::sort(ranges.begin(), ranges.end(), [](Range one, Range other) { return one.from < other.from; }); std::vector merged_ranges = std::ranges::fold_left( ranges, std::vector(), [](std::vector acc, Range range) { if (acc.empty() || acc.back().to < range.from) { acc.push_back(range); } else { acc.back().to = std::max(range.to, acc.back().to); } return acc; }); std::vector ids{}; { auto stream = std::stringstream(data_ids); for (std::string t; std::getline(stream, t);) { auto id = std::stoll(t); ids.push_back(id); } } long long password_part_1 = 0; std::ranges::for_each(ids, [&merged_ranges, &password_part_1](long long id) { bool is_fresh = false; // guilty until proven innocent! for (auto range : merged_ranges) { is_fresh = range.contains(id); if (is_fresh) { break; } } if (is_fresh) { password_part_1 += 1; } }); long long password_part_2 = 0; for (auto range : merged_ranges) { password_part_2 += range.size(); std::println("{} - {}", range.from, range.to); } std::println("Eureka! {} / {}", password_part_1, password_part_2); return 0; }