Advent of Code 2025, done in C++
at main 142 lines 3.9 kB view raw
1#include <cstddef> 2#include <format> 3#include <fstream> 4#include <map> 5#include <print> 6#include <string> 7#include <vector> 8 9#include "common/getinputpath.h" 10 11void render(std::vector<std::string>& data) { 12 if (data.size() < 2) { 13 return; 14 } 15 16 for (size_t i = 1; i < data.size(); ++i) { 17 auto& previous = data[i - 1]; 18 auto& current = data[i]; 19 20 for (size_t ch = 0; ch < current.size(); ++ch) { 21 char previous_ch = previous[ch]; 22 char current_ch = current[ch]; 23 if (previous_ch != 'S' && previous_ch != '|') { 24 continue; 25 } 26 27 // render 28 if (current_ch == '^') { 29 // split 30 if (ch > 0) { 31 current[ch - 1] = '|'; 32 } 33 if (ch < current.size()) { 34 current[ch + 1] = '|'; 35 } 36 } else { 37 current[ch] = '|'; 38 } 39 } 40 } 41} 42 43long long count_beams_split(std::vector<std::string>& data) { 44 if (data.size() < 2) { 45 return 0; 46 } 47 auto out = 0; 48 49 for (size_t i = 1; i < data.size(); ++i) { 50 auto& previous = data[i - 1]; 51 auto& current = data[i]; 52 53 for (size_t ch = 0; ch < current.size(); ++ch) { 54 if (previous[ch] == '|' && current[ch] == '^') { 55 out += 1; 56 } 57 } 58 } 59 60 return out; 61} 62 63struct Position { 64 size_t x = 0; 65 size_t y = 0; 66 67 bool operator==(const Position& other) const { 68 return x == other.x && y == other.y; 69 } 70 71 bool operator<(const Position& other) const { 72 return y < other.y || (y == other.y && x < other.x); 73 } 74}; 75 76long long count_possible_paths(std::vector<std::string>& data, 77 Position position, 78 std::map<Position, long long>& cache) { 79 // TODO 80 if (position.y == data.size()) { // if we reached bottom 81 return 1; 82 } 83 long long result = 0; 84 if (data[position.y][position.x] == '|' || 85 data[position.y][position.x] == 'S') { 86 Position new_pos{.x = position.x, .y = position.y + 1}; 87 result = count_possible_paths(data, new_pos, cache); 88 89 } else if (data[position.y][position.x] == '^') { 90 Position left = Position{.x = position.x - 1, .y = position.y}; 91 Position right = Position{.x = position.x + 1, .y = position.y}; 92 93 // a weird workaround to satisfy some static checks. maps must 94 // be sortable. 95 if (cache.contains(position)) { 96 result = cache[position]; 97 } else { 98 result = count_possible_paths(data, left, cache) + 99 count_possible_paths(data, right, cache); 100 101 cache[position] = result; 102 } 103 } 104 105 return result; 106} 107 108long long count_possible_paths(std::vector<std::string>& data, 109 std::map<Position, long long>& cache) { 110 Position start{ 111 .x = data[0].find_first_of('S'), 112 .y = 0, 113 }; 114 return count_possible_paths(data, start, cache); 115} 116 117// runtime on Ryzen 5 5600G: 0.003s 118int main() { 119 auto data_path = get_input_path(DATA_FOLDER); 120 std::ifstream data_ifstream(data_path); 121 if (!data_ifstream.is_open()) { 122 std::println("Cannot open the file at {}", data_path.string()); 123 return 1; 124 } 125 126 std::vector<std::string> data{}; 127 for (std::string t; std::getline(data_ifstream, t);) { 128 data.push_back(t); 129 } 130 131 render(data); // this has some great potential for TUI visualization 132 133 long long password_part_1 = count_beams_split(data); 134 135 std::map<Position, long long> cache{}; 136 long long password_part_2 = 137 count_possible_paths(data, cache); // this one too 138 139 std::println("Eureka! {} / {}", password_part_1, password_part_2); 140 141 return 0; 142}