+30
-22
src/02/solution.cxx
+30
-22
src/02/solution.cxx
···
4
4
#include <format>
5
5
#include <fstream>
6
6
#include <functional>
7
+
#include <iterator>
7
8
#include <print>
8
9
#include <ranges>
9
10
#include <regex>
10
11
#include <string>
12
+
#include <vector>
11
13
12
14
#ifndef DATA_FOLDER
13
15
#error \
···
23
25
bool part2_valid;
24
26
};
25
27
26
-
NumberProfile is_valid(long id) {
28
+
[[nodiscard]] NumberProfile is_valid(long id) {
27
29
std::string id_string = std::to_string(id);
28
30
29
31
bool part1_valid = true;
30
32
bool part2_valid = true;
31
-
32
-
for (unsigned long i = 1; i <= id_string.length(); ++i) {
33
-
auto substring = id_string.substr(0, i);
34
-
auto regex_str_part_1 = std::format("({}){{2}}", substring);
35
-
auto regex_str_part_2 = std::format("({}){{2,}}", substring);
36
-
auto regex_part_1 = std::regex(regex_str_part_1);
37
-
auto regex_part_2 = std::regex(regex_str_part_2);
38
-
if (part1_valid) {
39
-
part1_valid = !std::regex_match(id_string, regex_part_1);
40
-
}
41
-
if (part2_valid) {
42
-
part2_valid = !std::regex_match(id_string, regex_part_2);
43
-
}
44
-
if (!part1_valid && !part2_valid) {
45
-
break;
46
-
}
33
+
34
+
// repeats 2 times
35
+
if (id_string.length() % 2 == 0 && part1_valid) {
36
+
bool invalid = id_string.substr(0, id_string.length() / 2) ==
37
+
id_string.substr(id_string.length() / 2);
38
+
part1_valid = !invalid;
39
+
}
40
+
41
+
// repeats more than 2 times
42
+
if (id_string.length() >= 2 && part2_valid) {
43
+
auto t = id_string + id_string;
44
+
part2_valid =
45
+
t.substr(1, t.length() - 2).find(id_string) == std::string::npos;
47
46
}
48
47
49
48
return NumberProfile{
···
53
52
};
54
53
}
55
54
56
-
// Ryzen 5 5600G runtime: 25m51s
55
+
// Ryzen 5 5600G runtime: 1s494ms
57
56
int main() {
58
57
std::ifstream input(input_path);
59
58
if (!input.is_open()) {
···
71
70
auto left = t.substr(0, t.find('-'));
72
71
auto right = t.substr(t.find('-') + 1);
73
72
74
-
auto ids = std::ranges::views::iota(std::stol(left), std::stol(right) + 1) |
75
-
std::ranges::views::transform(is_valid);
73
+
auto ids = std::vector<NumberProfile>(std::stol(right) - std::stol(left));
74
+
75
+
{
76
+
auto ids_num = std::vector<long>(std::stol(right) - std::stol(left));
77
+
std::ranges::iota(ids_num.begin(), ids_num.end(), std::stol(left));
78
+
std::ranges::transform(ids_num, std::back_inserter(ids),
79
+
[](auto i) { return is_valid(i); });
80
+
}
81
+
76
82
auto invalid_ids_part1 =
77
83
ids | std::ranges::views::filter([](NumberProfile i) {
78
84
return !i.part1_valid;
···
85
91
}) |
86
92
std::ranges::views::transform([](NumberProfile i) { return i.number; });
87
93
88
-
auto sum_part1 = std::ranges::fold_left(invalid_ids_part1, 0, std::plus{});
94
+
auto sum_part1 =
95
+
std::ranges::fold_left(invalid_ids_part1, 0ULL, std::plus<>{});
89
96
password_part_1 += sum_part1;
90
97
91
-
auto sum_part2 = std::ranges::fold_left(invalid_ids_part2, 0, std::plus{});
98
+
auto sum_part2 =
99
+
std::ranges::fold_left(invalid_ids_part2, 0ULL, std::plus<>{});
92
100
password_part_2 += sum_part2;
93
101
}
94
102