Advent of Code 2025, done in C++
at main 3.8 kB view raw
1#include "common/getinputpath.h" 2#include <algorithm> 3#include <cstddef> 4#include <filesystem> 5#include <fstream> 6#include <functional> 7#include <optional> 8#include <print> 9#include <sstream> 10#include <string> 11#include <vector> 12 13int main() { 14 auto data_path = get_input_path(DATA_FOLDER); 15 auto data_size = std::filesystem::file_size(data_path); 16 std::ifstream data_ifstream(data_path); 17 if (!data_ifstream.is_open()) { 18 std::println("Failed to open input file at {}", data_path.string()); 19 return 1; 20 } 21 22 std::string data{}; 23 data.resize(data_size); 24 data_ifstream.read(data.data(), data_size); 25 26 long long password_part_1 = 0; 27 // password_part_2 requires a whole different way of parsing data. look for 28 // the next block. 29 { 30 std::vector<std::vector<std::string>> data_p1{}; 31 std::stringstream data_ss(data); 32 for (std::string t; std::getline(data_ss, t);) { 33 std::stringstream t_stream(t); 34 35 std::string word; 36 std::vector<std::string> words{}; 37 // stringstream >> buffer_string skips all whitespaces (space, tab, \n, 38 // etc.) and overwrites the buffer_string. 39 while (t_stream >> word) { 40 words.push_back(word); 41 } 42 data_p1.push_back(words); 43 } 44 45 // now, calculations. 46 47 for (size_t i = 0; i < data_p1[0].size(); ++i) { 48 std::optional<long long> subtotal = std::nullopt; 49 std::string operation = data_p1.back()[i]; 50 51 for (size_t j = 0; j < data_p1.size() - 1; ++j) { 52 if (!subtotal.has_value()) { 53 subtotal = std::stoll(data_p1[j][i]); 54 continue; 55 } 56 57 switch (operation[0]) { 58 case '+': { 59 subtotal = subtotal.value() + std::stoll(data_p1[j][i]); 60 break; 61 } 62 case '*': { 63 subtotal = subtotal.value() * std::stoll(data_p1[j][i]); 64 break; 65 } 66 } 67 } 68 69 password_part_1 += subtotal.value(); 70 } 71 } 72 73 long long password_part_2 = 0; 74 // let's rotate the world 75 { 76 // splitting string by \n 77 std::vector<std::string> data_p2{}; 78 std::stringstream data_ss(data); 79 for (std::string t; std::getline(data_ss, t);) { 80 data_p2.push_back(t); 81 } 82 83 // reading it like Japanese hiragana in traditional (vertical, 84 // right-to-left) writing 85 std::vector<std::string> rotated_data{}; 86 for (long i = data_p2[0].size() - 1; i >= 0; --i) { 87 std::string buffer_string{}; 88 for (size_t j = 0; j < data_p2.size(); ++j) { 89 if (data_p2[j][i] == ' ') { 90 continue; 91 } 92 93 buffer_string.push_back(data_p2[j][i]); 94 } 95 if (!buffer_string.empty()) { 96 rotated_data.push_back(buffer_string); 97 } 98 } 99 100 std::vector<long long> acc{}; 101 std::vector<long long> solutions{}; 102 for (auto number : rotated_data) { 103 char last_character = number.back(); 104 switch (last_character) { 105 case '*': { 106 auto actual_number = number.substr(0, number.size() - 1); 107 acc.push_back(std::stoll(actual_number)); 108 long long solution = 109 std::ranges::fold_left(acc, 1LL, std::multiplies<>()); 110 solutions.push_back(solution); 111 acc = std::vector<long long>(); 112 continue; 113 break; 114 } 115 case '+': { 116 auto actual_number = number.substr(0, number.size() - 1); 117 acc.push_back(std::stoll(actual_number)); 118 long long solution = std::ranges::fold_left(acc, 0LL, std::plus<>()); 119 solutions.push_back(solution); 120 acc = std::vector<long long>(); 121 continue; 122 break; 123 } 124 } 125 126 acc.push_back(std::stoll(number)); 127 } 128 129 password_part_2 = std::ranges::fold_left(solutions, 0LL, std::plus<>()); 130 } 131 132 std::println("Eureka! {} / {}", password_part_1, password_part_2); 133 134 return 0; 135}