+36
-21
src/01/solution.cxx
+36
-21
src/01/solution.cxx
···
2
2
#include <algorithm>
3
3
#include <cstdlib>
4
4
#include <filesystem>
5
+
#include <format>
5
6
#include <fstream>
6
7
#include <print>
7
-
#include <ranges>
8
8
#include <string>
9
9
#include <string_view>
10
10
···
18
18
int value = 50;
19
19
};
20
20
21
+
struct RotationResult {
22
+
int new_value;
23
+
int crossed_0;
24
+
};
25
+
21
26
// @return how many times the rotary crossed 0, but *not* the times it stopped
22
27
// at 0
23
-
int rotate(Rotary &rotary, int value) {
28
+
RotationResult rotate(const Rotary &rotary, const int value) {
24
29
int result = rotary.value + value;
25
-
int crossed_0 = 0;
30
+
31
+
int begin = std::min(result, rotary.value);
32
+
int end = std::max(result, rotary.value);
26
33
27
-
int begin = std::min(result, rotary.value); // looks modern, but it's really
28
-
int end = std::max(result, rotary.value); // hideous
29
-
auto range = std::ranges::views::iota(begin + 1, end) |
30
-
std::ranges::views::filter([](int x) { return x % 100 == 0; });
34
+
auto begin_norm = 0;
35
+
if (begin % 100 != 0) {
36
+
if (begin >= 0) {
37
+
begin_norm = begin - (begin % 100);
38
+
} else {
39
+
begin_norm = (begin - 100) / 100 * 100;
40
+
}
41
+
} else {
42
+
begin_norm = begin;
43
+
}
31
44
32
-
for (int _ : range) { // Kotlin .forEach would have looked so much better
33
-
crossed_0 += 1;
45
+
auto end_norm = 0;
46
+
if (end % 100 != 0) {
47
+
end_norm = end + (100 - end % 100);
48
+
} else {
49
+
end_norm = end;
34
50
}
35
51
36
-
while (result < 0) {
37
-
result += 100;
52
+
auto crossed_0 = (end_norm - begin_norm) / 100 - 1;
53
+
54
+
if (result < 0) {
55
+
result += std::abs(result / 100 * 100) + 100;
38
56
}
39
-
while (result > 99) {
40
-
result -= 100;
57
+
if (result > 99) {
58
+
result %= 100;
41
59
}
42
-
rotary.value = result;
43
60
44
-
return crossed_0;
61
+
return RotationResult{.new_value = result, .crossed_0 = crossed_0};
45
62
}
46
63
47
64
int main() {
···
69
86
// horrendous code below
70
87
71
88
for (std::string line; std::getline(input, line);) {
89
+
// parser is okay-ish, I trust AoC inputs
72
90
std::string_view rotation = std::string_view(line.data(), 1);
73
91
std::string_view number_sv = std::string_view(line.data() + 1);
74
92
75
93
auto number = std::stoi(number_sv.data());
76
-
77
94
if (rotation == "L") {
78
95
number = -number;
79
96
}
80
97
81
-
// ridiculous - a function has both side effect and a return value
82
-
// this shit reminds me of out parameter convention so much...
83
-
times_crossed_0 += rotate(rotary, number);
84
-
98
+
auto result = rotate(rotary, number);
99
+
times_crossed_0 += result.crossed_0;
100
+
rotary.value = result.new_value;
85
101
if (rotary.value == 0) {
86
102
password_part_1 += 1;
87
103
}
···
91
107
92
108
std::println("Eureka! {} / {}", password_part_1, password_part_2);
93
109
94
-
input.close();
95
110
return 0;
96
111
}