Advent of Code 2025, done in C++
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}