Skip to content

Commit fdf7517

Browse files
author
Christian Lundh
committed
C++23 2024 day 14
1 parent 85c7d30 commit fdf7517

File tree

3 files changed

+145
-1
lines changed

3 files changed

+145
-1
lines changed

C++/2024/aoc_2024_14.cpp

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
#include "aoc_io.hpp"
2+
#include "aoc_timer.hpp"
3+
#include <algorithm>
4+
#include <cstdint>
5+
#include <iterator>
6+
#include <ranges>
7+
#include <set>
8+
#include <vector>
9+
10+
using Robot = std::pair<std::pair<int, int>, std::pair<int, int>>;
11+
12+
[[nodiscard]] auto parse_instructions(const std::vector<std::string> &instructions) -> std::vector<Robot> {
13+
auto robots = std::vector<Robot>{};
14+
std::ranges::transform(instructions, std::back_inserter(robots), [](const auto &s) -> Robot {
15+
auto s1 = s.substr(s.find('=') + 1, s.find(' '));
16+
auto s2 = s.substr(s.find('v') + 2, s.npos);
17+
auto p1 = std::stoi(s1);
18+
auto p2 = std::stoi(s1.substr(s1.find(',') + 1, s1.npos));
19+
auto p3 = std::stoi(s2);
20+
auto p4 = std::stoi(s2.substr(s2.find(',') + 1, s2.npos));
21+
22+
auto pp1 = std::pair{p1, p2};
23+
auto pp2 = std::pair{p3, p4};
24+
return {pp1, pp2};
25+
});
26+
return robots;
27+
}
28+
29+
void move_robot(Robot &r, const auto &steps) {
30+
auto &[position, velocity] = r;
31+
auto &[x, y] = position;
32+
auto &[vx, vy] = velocity;
33+
34+
x += steps * vx;
35+
y += steps * vy;
36+
}
37+
38+
auto get_limits(const std::vector<Robot> &robots) {
39+
auto max_x_pair = std::ranges::max(robots, {}, [](const auto &v) {
40+
return v.first.first;
41+
});
42+
auto max_y_pair = std::ranges::max(robots, {}, [](const auto &v) {
43+
return v.first.second;
44+
});
45+
return std::pair{max_x_pair.first.first + 1, max_y_pair.first.second + 1};
46+
}
47+
48+
[[nodiscard]] auto solve_part_1(const std::vector<Robot> &instructions) -> uint32_t {
49+
const auto iterations = 100;
50+
std::vector<Robot> robots = instructions;
51+
52+
const auto [max_x, max_y] = get_limits(instructions);
53+
for (auto &robot : robots) {
54+
move_robot(robot, iterations);
55+
auto &[position, velocity] = robot;
56+
position.first = position.first % max_x;
57+
position.second = position.second % max_y;
58+
if (position.first < 0)
59+
position.first += max_x;
60+
if (position.second < 0)
61+
position.second += max_y;
62+
}
63+
64+
const auto quadrants = std::vector<std::pair<std::pair<int, int>, std::pair<int, int>>>{
65+
{{0, 0}, {max_x / 2, max_y / 2}},
66+
{{max_x / 2 + 1, 0}, {max_x, max_y / 2} },
67+
{{0, max_y / 2 + 1}, {max_x / 2, max_y} },
68+
{{max_x / 2 + 1, max_y / 2 + 1}, {max_x, max_y} }
69+
};
70+
71+
auto result = uint32_t{1};
72+
for (auto &quadrant : quadrants) {
73+
result *= std::ranges::count_if(robots, [&quadrant](const auto &r) {
74+
auto [position, velocity] = r;
75+
auto [l1, l2] = quadrant;
76+
if (!((l1.first <= position.first) && (position.first < l2.first)))
77+
return false;
78+
if (!((l1.second <= position.second) && (position.second < l2.second)))
79+
return false;
80+
return true;
81+
});
82+
}
83+
return result;
84+
}
85+
86+
auto all_unique_positions(const std::vector<Robot> &robots) -> bool {
87+
auto field = std::set<std::pair<int, int>>{};
88+
std::ranges::for_each(robots, [&field](const auto &r) {
89+
field.insert({r.first.first, r.first.second});
90+
});
91+
return (robots.size() == field.size());
92+
}
93+
94+
[[nodiscard]] auto solve_part_2(const std::vector<Robot> &instructions) -> int {
95+
96+
std::vector<Robot> robots = instructions;
97+
auto [max_x, max_y] = get_limits(instructions);
98+
auto result = int{};
99+
while (!all_unique_positions(robots)) {
100+
for (auto &robot : robots) {
101+
move_robot(robot, 1);
102+
auto &[position, velocity] = robot;
103+
position.first = position.first % max_x;
104+
position.second = position.second % max_y;
105+
if (position.first < 0)
106+
position.first += max_x;
107+
if (position.second < 0)
108+
position.second += max_y;
109+
}
110+
++result;
111+
}
112+
return result;
113+
}
114+
115+
void solve_all(const std::vector<std::string> &instructions) {
116+
auto parsed_instructions = aoc::timer(parse_instructions, instructions, "Preparation time:");
117+
aoc::timer(1, solve_part_1, parsed_instructions);
118+
aoc::timer(2, solve_part_2, parsed_instructions);
119+
}
120+
121+
auto main(int argc, char **argv) -> int {
122+
std::string filename;
123+
constexpr int year = 2024;
124+
constexpr int day = 14;
125+
126+
auto args = std::span(argv, argc);
127+
if (argc > 1) {
128+
if (std::string(args[1]) == "--test") {
129+
filename = "test_input.txt";
130+
} else {
131+
filename = args[1];
132+
}
133+
} else {
134+
filename = "input.txt";
135+
}
136+
137+
auto instructions = aoc::io::get_input_list<std::string>(filename, year, day);
138+
139+
aoc::io::header(year, day);
140+
aoc::timer(solve_all, instructions);
141+
142+
return 0;
143+
}

C++/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ While I try to learn the benefits and caveats of C++ I also decided to take on t
1717
| 9 | &#11088;&#11088; | | |
1818
| 10 | &#11088;&#11088; | | |
1919
| 11 | &#11088;&#11088; | | |
20+
| 14 | &#11088;&#11088; | | |
2021

2122
## 2023:
2223
| Day | Stars | Timing Part 1 | Timing Part 2 | Comment

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Solutions for [Advent of Code](https://adventofcode.com) in different languages.
55
## Year 2024
66
+ 22 &#11088; in [Python](python/README.md)
77
+ 17 &#11088; in [C](C/README.md)
8-
+ 20 &#11088; in [C++](C++/README.md)
8+
+ 22 &#11088; in [C++](C++/README.md)
99
+ 1 &#11088; in [Rust](Rust/README.md)
1010

1111
## Year 2023

0 commit comments

Comments
 (0)