aboutsummaryrefslogtreecommitdiff
path: root/2024/src/day15.cpp
diff options
context:
space:
mode:
authorThomas Schmucker <ts@its1.de>2024-12-15 17:09:27 +0100
committerThomas Schmucker <ts@its1.de>2024-12-15 17:09:27 +0100
commite733679389d4facd44055dc7844a0441c5bee02e (patch)
tree29cc3ae1393c73e9523ec5ec55df8d2beacf0b3c /2024/src/day15.cpp
parentaa823e8292ac80127c903aff8c783cb5d2f875db (diff)
downloadadvent-of-code-e733679389d4facd44055dc7844a0441c5bee02e.tar.gz
advent-of-code-e733679389d4facd44055dc7844a0441c5bee02e.tar.bz2
advent-of-code-e733679389d4facd44055dc7844a0441c5bee02e.zip
aoc 2024, day 15, part 2 & bugfixes
Diffstat (limited to '2024/src/day15.cpp')
-rw-r--r--2024/src/day15.cpp216
1 files changed, 205 insertions, 11 deletions
diff --git a/2024/src/day15.cpp b/2024/src/day15.cpp
index 5c2449b..94b8a2b 100644
--- a/2024/src/day15.cpp
+++ b/2024/src/day15.cpp
@@ -1,3 +1,4 @@
1#include <cassert>
1#include <fstream> 2#include <fstream>
2#include <iostream> 3#include <iostream>
3#include <map> 4#include <map>
@@ -8,10 +9,12 @@
8#include <tuple> 9#include <tuple>
9using namespace std; 10using namespace std;
10 11
11using pos_type = tuple<size_t, size_t>; 12using pos_type = tuple<size_t, size_t>;
12using room_type = set<pos_type>; 13using room_type = set<pos_type>;
13using boxes_type = set<pos_type>; 14using boxes_type = set<pos_type>;
14using puzzle_type = tuple<room_type, boxes_type, string, pos_type>; 15using boxes2_type = map<pos_type, bool>;
16using puzzle_type = tuple<room_type, boxes_type, string, pos_type>;
17using puzzle2_type = tuple<room_type, boxes2_type, string, pos_type>;
15 18
16puzzle_type 19puzzle_type
17read_file(string_view filename) 20read_file(string_view filename)
@@ -51,12 +54,59 @@ read_file(string_view filename)
51 return { room, boxes, movements, start }; 54 return { room, boxes, movements, start };
52} 55}
53 56
54/* 57puzzle2_type
58read_file2(string_view filename)
59{
60 fstream input{ filename };
61 room_type room;
62 boxes2_type boxes;
63 string movements;
64 pos_type start;
65
66 size_t yPos = 0;
67 for ( string line; getline(input, line); ) {
68 if ( line.empty() ) {
69 continue;
70 }
71
72 if ( line[0] == '#' ) {
73 for ( size_t xPos = 0; xPos != line.size(); ++xPos ) {
74 auto chr = line.at(xPos);
75 if ( chr == '#' ) {
76 room.emplace(xPos * 2, yPos);
77 room.emplace(xPos * 2 + 1, yPos);
78 }
79 else if ( chr == 'O' ) {
80 boxes.insert({ pos_type(xPos * 2, yPos), true });
81 boxes.insert({ pos_type(xPos * 2 + 1, yPos), false });
82 }
83 else if ( chr == '@' ) {
84 start = { xPos * 2, yPos };
85 }
86 }
87 ++yPos;
88 }
89 else {
90 movements += line;
91 }
92 }
93
94 return { room, boxes, movements, start };
95}
96
55void 97void
56print(const room_type& room, const boxes_type& boxes, const pos_type& pos) 98print(const room_type& room, const boxes_type& boxes, const pos_type& pos)
57{ 99{
58 for ( size_t yPos = 0; yPos != 10; ++yPos ) { 100 size_t width = 0;
59 for ( size_t xPos = 0; xPos != 10; ++xPos ) { 101 size_t height = 0;
102
103 for ( const auto& [x, y]: room ) {
104 width = max(width, x + 1);
105 height = max(height, y + 1);
106 }
107
108 for ( size_t yPos = 0; yPos != height; ++yPos ) {
109 for ( size_t xPos = 0; xPos != width; ++xPos ) {
60 if ( pos == pos_type{ xPos, yPos } ) { 110 if ( pos == pos_type{ xPos, yPos } ) {
61 cout << '@'; 111 cout << '@';
62 } 112 }
@@ -67,14 +117,45 @@ print(const room_type& room, const boxes_type& boxes, const pos_type& pos)
67 cout << 'O'; 117 cout << 'O';
68 } 118 }
69 else { 119 else {
70 cout << ' '; 120 cout << '.';
121 }
122 }
123 cout << '\n';
124 }
125 cout << endl;
126}
127
128void
129print(const room_type& room, const boxes2_type& boxes, const pos_type& pos)
130{
131 size_t width = 0;
132 size_t height = 0;
133
134 for ( const auto& [x, y]: room ) {
135 width = max(width, x + 1);
136 height = max(height, y + 1);
137 }
138
139 for ( size_t yPos = 0; yPos != height; ++yPos ) {
140 for ( size_t xPos = 0; xPos != width; ++xPos ) {
141 if ( pos == pos_type{ xPos, yPos } ) {
142 cout << '@';
143 }
144 else if ( room.contains({ xPos, yPos }) ) {
145 cout << '#';
146 }
147 else if ( boxes.contains({ xPos, yPos }) ) {
148 auto value = boxes.at({ xPos, yPos });
149 cout << (value ? '[' : ']');
150 }
151 else {
152 cout << '.';
71 } 153 }
72 } 154 }
73 cout << '\n'; 155 cout << '\n';
74 } 156 }
75 cout << endl; 157 cout << endl;
76} 158}
77*/
78 159
79optional<boxes_type> 160optional<boxes_type>
80can_move(const room_type& room, const boxes_type& boxes, pos_type start, pos_type direction) // NOLINT 161can_move(const room_type& room, const boxes_type& boxes, pos_type start, pos_type direction) // NOLINT
@@ -132,9 +213,122 @@ part1(const puzzle_type& puzzle)
132 }) << endl; 213 }) << endl;
133} 214}
134 215
216tuple<pos_type, pos_type>
217get_both_parts(const boxes2_type& boxes, pos_type pos)
218{
219 const auto [x, y] = pos;
220 if ( boxes.at(pos) ) {
221 return { pos, { x + 1, y } };
222 }
223 else {
224 return { { x - 1, y }, pos };
225 }
226}
227
228optional<boxes2_type>
229can_move(const room_type& room, const boxes2_type& all_boxes, pos_type start, pos_type direction) // NOLINT
230{
231 function<optional<boxes2_type>(const boxes2_type&, size_t)> can_move_up_down = [&room, &all_boxes, &can_move_up_down](const boxes2_type& boxes, size_t dy) -> optional<boxes2_type> {
232 boxes2_type candidates;
233
234 for ( const auto& [pos, b]: boxes ) {
235 const auto [x, y] = pos;
236 pos_type try_pos(x, y + dy);
237
238 if ( room.contains(try_pos) ) {
239 return nullopt;
240 }
241
242 if ( all_boxes.contains(try_pos) ) {
243 const auto [lhs, rhs] = get_both_parts(all_boxes, try_pos);
244
245 assert(all_boxes.contains(lhs) && all_boxes.at(lhs) == true); // NOLINT
246 assert(all_boxes.contains(rhs) && all_boxes.at(rhs) == false); // NOLINT
247
248 candidates.emplace(lhs, true);
249 candidates.emplace(rhs, false);
250 }
251 }
252
253 if ( candidates.empty() ) {
254 return boxes2_type{};
255 }
256
257 if ( auto results = can_move_up_down(candidates, dy) ) {
258 for ( const auto& result: results.value() ) {
259 candidates.insert(result);
260 }
261 return candidates;
262 }
263
264 return nullopt;
265 };
266
267 const auto [x, y] = start;
268 const auto [dx, dy] = direction;
269
270 if ( dy != 0 ) {
271 return can_move_up_down({ { start, false } }, dy);
272 }
273
274 boxes2_type candidates;
275
276 size_t steps = 1;
277 while ( all_boxes.contains({ x + dx * steps, y + dy * steps }) ) {
278 auto foo = all_boxes.at({ x + dx * steps, y + dy * steps });
279 candidates.insert({ { x + dx * steps, y + dy * steps }, foo });
280 ++steps;
281 }
282
283 if ( room.contains({ x + dx * steps, y + dy * steps }) ) {
284 return nullopt;
285 }
286
287 return candidates;
288}
289
290void
291part2(const puzzle2_type& puzzle)
292{
293 map<char, pos_type> deltas = {
294 { '<', { -1, 0 } }, // Left
295 { '^', { 0, -1 } }, // Up
296 { '>', { 1, 0 } }, // Right
297 { 'v', { 0, 1 } } // Down
298 };
299
300 auto [room, boxes, movements, start] = puzzle;
301
302 for ( auto chr: movements ) {
303 const auto delta = deltas[chr];
304 if ( auto bitw = can_move(room, boxes, start, delta) ) {
305 const auto [dx, dy] = delta;
306
307 get<0>(start) += dx;
308 get<1>(start) += dy;
309
310 for ( const auto& [box, b]: bitw.value() ) {
311 boxes.erase(box);
312 }
313
314 for ( auto [pos, b]: bitw.value() ) {
315 const auto [x, y] = pos;
316 boxes.emplace(pos_type{ x + dx, y + dy }, b);
317 }
318 }
319 }
320
321 cout << accumulate(boxes.begin(), boxes.end(), 0UL, [](auto init, const auto& box) {
322 const auto& [pos, b] = box;
323 if ( !b ) {
324 return init;
325 }
326 return init + get<0>(pos) + 100 * get<1>(pos);
327 }) << endl;
328}
135int 329int
136main() 330main()
137{ 331{
138 const auto data = read_file("data/day15.txt"); 332 part1(read_file("data/day15.txt"));
139 part1(data); 333 part2(read_file2("data/day15.txt"));
140} 334}