+11
-23
src/07/solution.cxx
+11
-23
src/07/solution.cxx
···
63
size_t x = 0;
64
size_t y = 0;
65
66
-
bool operator==(Position other) {
67
-
return this->x == other.x && this->y == other.y;
68
}
69
70
-
bool operator<(Position other) {
71
-
return this->x < other.x && this->y < other.y;
72
-
}
73
-
74
-
// std::map is a *sorted* structure, so it requires its types to implement
75
-
// comparators or not use std::map with unsortable values at all. I did not
76
-
// want to implement a comparator at the moment. this is part of a workaround.
77
-
std::string encode() { return std::format("{}/{}", this->x, this->y); }
78
-
79
-
static Position decode(std::string position) {
80
-
auto slash_idx = position.find_first_of('/');
81
-
auto x = std::stoll(position.substr(0, slash_idx));
82
-
auto y = std::stoll(position.substr(slash_idx + 1));
83
-
return Position{.x = static_cast<size_t>(x), .y = static_cast<size_t>(y)};
84
}
85
};
86
87
long long count_possible_paths(std::vector<std::string> &data,
88
Position position,
89
-
std::map<std::string, long long> &cache) {
90
// TODO
91
if (position.y == data.size()) { // if we reached bottom
92
return 1;
···
103
Position right = Position{.x = position.x + 1, .y = position.y};
104
105
// a weird workaround to satisfy some static checks. maps must be sortable.
106
-
if (cache.contains(position.encode())) {
107
-
result = cache[position.encode()];
108
} else {
109
result = count_possible_paths(data, left, cache) +
110
count_possible_paths(data, right, cache);
111
112
-
cache[position.encode()] = result;
113
}
114
}
115
···
117
}
118
119
long long count_possible_paths(std::vector<std::string> &data,
120
-
std::map<std::string, long long> &cache) {
121
Position start{
122
.x = data[0].find_first_of('S'),
123
.y = 0,
···
125
return count_possible_paths(data, start, cache);
126
}
127
128
-
// runtime on Ryzen 5 5600G: 0.004s
129
int main() {
130
auto data_path = get_input_path(DATA_FOLDER);
131
std::ifstream data_ifstream(data_path);
···
143
144
long long password_part_1 = count_beams_split(data);
145
146
-
std::map<std::string, long long> cache{};
147
long long password_part_2 = count_possible_paths(data, cache); // this one too
148
149
std::println("Eureka! {} / {}", password_part_1, password_part_2);
···
63
size_t x = 0;
64
size_t y = 0;
65
66
+
bool operator==(const Position& other) const {
67
+
return x == other.x && y == other.y;
68
}
69
70
+
bool operator<(const Position& other) const {
71
+
return y < other.y || (y == other.y && x < other.x);
72
}
73
};
74
75
long long count_possible_paths(std::vector<std::string> &data,
76
Position position,
77
+
std::map<Position, long long> &cache) {
78
// TODO
79
if (position.y == data.size()) { // if we reached bottom
80
return 1;
···
91
Position right = Position{.x = position.x + 1, .y = position.y};
92
93
// a weird workaround to satisfy some static checks. maps must be sortable.
94
+
if (cache.contains(position)) {
95
+
result = cache[position];
96
} else {
97
result = count_possible_paths(data, left, cache) +
98
count_possible_paths(data, right, cache);
99
100
+
cache[position] = result;
101
}
102
}
103
···
105
}
106
107
long long count_possible_paths(std::vector<std::string> &data,
108
+
std::map<Position, long long> &cache) {
109
Position start{
110
.x = data[0].find_first_of('S'),
111
.y = 0,
···
113
return count_possible_paths(data, start, cache);
114
}
115
116
+
// runtime on Ryzen 5 5600G: 0.003s
117
int main() {
118
auto data_path = get_input_path(DATA_FOLDER);
119
std::ifstream data_ifstream(data_path);
···
131
132
long long password_part_1 = count_beams_split(data);
133
134
+
std::map<Position, long long> cache{};
135
long long password_part_2 = count_possible_paths(data, cache); // this one too
136
137
std::println("Eureka! {} / {}", password_part_1, password_part_2);