-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday05.hpp
217 lines (186 loc) · 6.55 KB
/
day05.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#include <charconv>
#include <execution>
#include <string_view>
#include <fmt/core.h>
#include <fmt/ranges.h>
#include <range/v3/all.hpp>
#include <exec/inline_scheduler.hpp>
#include <stdexec/execution.hpp>
namespace {
using std::string_view_literals::operator""sv;
namespace rv = ranges::views;
constexpr std::string_view DIGITS{"0123456789"sv};
struct entry {
entry(long dst, long src, long count) noexcept
: src{src}, dst{dst}, count{count} {}
[[nodiscard]] constexpr inline bool in_range(long i) const noexcept {
return src <= i and i < src + count;
}
[[nodiscard]] constexpr inline long map_value(long i) const noexcept {
return i + (dst - src);
}
constexpr auto operator<=>(entry const &rhs) const noexcept = default;
long src, dst, count;
};
struct map {
map(std::string_view text) {
while (text.find('\n') == 0) {
text.remove_prefix(1);
}
text.remove_prefix(text.find('\n') + 1);
while (not text.empty()) {
auto fence1 = text.find(' ');
auto fence2 = text.find(' ', fence1 + 1);
auto end = text.find('\n');
if (end == 0) {
break;
}
std::string_view const num1{text.substr(0, fence1)};
std::string_view const num2{text.substr(fence1 + 1, fence2 - fence1 - 1)};
std::string_view const num3{text.substr(fence2 + 1, end - fence2 - 1)};
long dst, src, count;
std::from_chars(num1.begin(), num1.end(), dst);
std::from_chars(num2.begin(), num2.end(), src);
std::from_chars(num3.begin(), num3.end(), count);
entries.emplace_back(dst, src, count);
text.remove_prefix(end + 1);
}
}
[[nodiscard]] inline long map_value(long src) const noexcept {
auto not_in_range = [=](entry const &e) { return not e.in_range(src); };
auto sat = entries | rv::drop_while(not_in_range);
if (not sat.empty()) {
return ranges::begin(sat)->map_value(src);
} else {
return src;
}
}
std::vector<entry> entries;
};
auto get_seeds(std::string_view nums) {
std::vector<long> values;
long v;
while (not nums.empty()) {
auto start = nums.find_first_of(DIGITS);
if (start == std::string_view::npos) {
break;
}
auto stop = nums.find_first_not_of(DIGITS, start);
if (stop == std::string_view::npos) {
stop = nums.size();
}
auto const n = nums.substr(start, stop - start);
std::from_chars(n.begin(), n.end(), v);
values.push_back(v);
nums.remove_prefix(stop);
}
return values;
}
struct input {
input(std::string_view data) {
auto end_of_seeds = data.find("\n\n");
seeds = get_seeds(data.substr(0, end_of_seeds));
data.remove_prefix(end_of_seeds + 2);
while (not data.empty()) {
if (auto end = data.find("\n\n"); end == std::string_view::npos) {
mappings.emplace_back(data);
data.remove_prefix(data.size());
} else {
mappings.emplace_back(data.substr(0, end + 1));
data.remove_prefix(end + 2);
}
}
}
std::vector<long> seeds;
std::vector<map> mappings;
};
auto parse([[maybe_unused]] auto scheduler, std::string_view data) {
return input{data};
}
auto get_min(std::span<long> totals) {
return std::reduce(std::execution::par_unseq, totals.begin(), totals.end(),
std::numeric_limits<long>::max(),
[](auto const &a, auto const &b) {
return std::min({a, b});
});
}
auto part1(auto scheduler, input const &data) {
std::span seeds{data.seeds};
std::span mappings{data.mappings};
auto process = [=](unsigned i, std::span<long> totals) {
auto id = seeds[i];
for (auto m : mappings) {
id = m.map_value(id);
}
totals[i] = id;
};
auto [value] =
stdexec::sync_wait(stdexec::just(std::vector<long>(seeds.size(), 0)) |
stdexec::let_value([=](std::vector<long> &totals) {
return stdexec::transfer_just(scheduler,
std::span{totals}) |
stdexec::bulk(seeds.size(), process) |
stdexec::transfer(exec::inline_scheduler{}) |
stdexec::then(get_min);
}))
.value();
return value;
}
auto calculate_path(long i, std::span<long> totals, long start,
std::span<map const> mappings) {
long id = i + start;
for (auto const &m : mappings) {
id = m.map_value(id);
}
totals[i] = id;
}
template <typename Scheduler>
auto parallel_process(std::vector<long> &totals, long start, long length,
std::span<long const> seeds,
std::span<map const> mappings, Scheduler scheduler) {
return stdexec::transfer_just(scheduler, std::span{totals}, start, mappings) |
stdexec::bulk(length, calculate_path) |
stdexec::transfer(exec::inline_scheduler{}) | stdexec::then(get_min);
}
template <typename Scheduler>
auto invoke(size_t i, long length, std::span<long const> seeds,
std::span<map const> mappings, Scheduler scheduler) {
return stdexec::just(std::vector<long>(length), seeds[2 * i], length, seeds,
mappings, scheduler) |
stdexec::let_value(parallel_process<Scheduler>);
}
template <typename Scheduler>
auto part2(Scheduler scheduler, input const &data,
[[maybe_unused]] long part1_answer) {
return 0l;
std::span seeds{data.seeds};
std::span mappings{data.mappings};
size_t const length{seeds.size() / 2};
auto process = [=](long i, long start, std::span<long> totals) {
auto id = start + i;
for (auto m : mappings) {
id = m.map_value(id);
}
totals[i] = id;
};
std::vector<long> results;
for (auto i : rv::closed_iota(0lu, length)) {
auto start = seeds[2 * i];
auto count = seeds[2 * i + 1];
auto [value] =
stdexec::sync_wait(stdexec::just(std::vector<long>(count, 0)) |
stdexec::let_value([=](std::vector<long> &totals) {
return stdexec::transfer_just(scheduler, start,
std::span{totals}) |
stdexec::bulk(count, process) |
stdexec::transfer(exec::inline_scheduler{}) |
stdexec::then([](auto, auto values) {
return get_min(values);
});
}))
.value();
results.push_back(value);
}
return get_min(results);
}
} // namespace