4
4
#include < cstdint>
5
5
#include < iterator>
6
6
#include < ranges>
7
- #include < set >
7
+ #include < unordered_set >
8
8
#include < vector>
9
9
10
- using Robot = std::pair<std::pair<int , int >, std::pair<int , int >>;
10
+ using Point = std::pair<int , int >;
11
+ using Robot = std::pair<Point, Point>;
12
+
13
+ template <>
14
+ struct std ::hash<std::pair<int , int >> {
15
+ auto operator ()(const pair<int , int > &v) const -> size_t {
16
+ return std::hash<int >()(v.first ) ^ std::hash<int >()(v.second );
17
+ }
18
+ };
11
19
12
20
[[nodiscard]] auto parse_instructions (const std::vector<std::string> &instructions) -> std::vector<Robot> {
13
21
auto robots = std::vector<Robot>{};
14
22
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};
23
+ const auto s1 = s.substr (s.find (' =' ) + 1 , s.find (' ' ));
24
+ const auto s2 = s.substr (s.find (' v' ) + 2 , s.npos );
25
+ const auto p1 = std::stoi (s1);
26
+ const auto p2 = std::stoi (s1.substr (s1.find (' ,' ) + 1 , s1.npos ));
27
+ const auto p3 = std::stoi (s2);
28
+ const auto p4 = std::stoi (s2.substr (s2.find (' ,' ) + 1 , s2.npos ));
29
+
30
+ return {
31
+ std::pair{p1, p2},
32
+ std::pair{p3, p4}
33
+ };
25
34
});
26
35
return robots;
27
36
}
28
37
29
- void move_robot (Robot &r, const auto & steps) {
38
+ void move_robot (Robot &r, const auto steps, const auto &limits ) {
30
39
auto &[position, velocity] = r;
31
40
auto &[x, y] = position;
32
41
auto &[vx, vy] = velocity;
33
42
34
- x += steps * vx;
35
- y += steps * vy;
43
+ auto &[max_x, max_y] = limits;
44
+
45
+ x = (max_x + (x + steps * vx) % max_x) % max_x;
46
+ y = (max_y + (y + steps * vy) % max_y) % max_y;
36
47
}
37
48
38
49
auto get_limits (const std::vector<Robot> &robots) {
@@ -49,33 +60,22 @@ auto get_limits(const std::vector<Robot> &robots) {
49
60
const auto iterations = 100 ;
50
61
std::vector<Robot> robots = instructions;
51
62
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
+ const auto limits = get_limits (instructions);
64
+ const auto [max_x, max_y] = limits;
65
+ std::ranges::for_each (robots, [&](auto &robot) {
66
+ move_robot (robot, iterations, limits);
67
+ });
63
68
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
+ const auto quadrants = std::array<std::pair<Point, Point>, 4 >{
70
+ {{{0 , 0 }, {max_x / 2 , max_y / 2 }}, {{max_x / 2 + 1 , 0 }, {max_x, max_y / 2 }}, {{0 , max_y / 2 + 1 }, {max_x / 2 , max_y}}, {{max_x / 2 + 1 , max_y / 2 + 1 }, {max_x, max_y}}}
69
71
};
70
72
71
73
auto result = uint32_t {1 };
72
74
for (auto &quadrant : quadrants) {
73
75
result *= std::ranges::count_if (robots, [&quadrant](const auto &r) {
74
76
auto [position, velocity] = r;
75
77
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 )))
78
+ if (!((l1.first <= position.first ) && (position.first < l2.first ) && (l1.second <= position.second ) && (position.second < l2.second )))
79
79
return false ;
80
80
return true ;
81
81
});
@@ -84,30 +84,24 @@ auto get_limits(const std::vector<Robot> &robots) {
84
84
}
85
85
86
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 ());
87
+ auto field = std::unordered_set<Point>{};
88
+ for (auto &robot : robots) {
89
+ auto [it, success] = field.insert (robot.first );
90
+ if (!success)
91
+ return false ;
92
+ }
93
+ return true ;
92
94
}
93
95
94
96
[[nodiscard]] auto solve_part_2 (const std::vector<Robot> &instructions) -> int {
95
97
96
98
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;
99
+ const auto limits = get_limits (instructions);
100
+ auto result = int {};
101
+ for (; !all_unique_positions (robots); ++result) {
102
+ std::ranges::for_each (robots, [&](auto &robot) {
103
+ move_robot (robot, 1 , limits);
104
+ });
111
105
}
112
106
return result;
113
107
}
0 commit comments