1
+ #include " common_headers.hpp"
2
+ #include " Position.hpp"
3
+
4
+ #include < cmath>
5
+ #include < regex>
6
+
7
+ struct RobotInfo final
8
+ {
9
+ Position position{};
10
+
11
+ int velocityX{};
12
+ int velocityY{};
13
+ };
14
+
15
+ [[nodiscard]] size_t solveFirstPart (const std::vector<RobotInfo>& inputVec)
16
+ {
17
+ constexpr size_t width{101 };
18
+ constexpr size_t height{103 };
19
+ constexpr size_t midVertical{(width / 2 ) + 1 };
20
+ constexpr size_t midHorizontal{(height / 2 ) + 1 };
21
+ std::array<int , 4 > counters{};
22
+ std::vector<std::vector<int >> map (height, std::vector<int >(width));
23
+
24
+ for (const auto & robot : inputVec) {
25
+ int64_t newX{robot.position .x + robot.velocityX * 100 };
26
+ int64_t newY{robot.position .y + robot.velocityY * 100 };
27
+ if (newX < 0 ) {
28
+ newX = (width - (std::abs (newX) % width)) % width;
29
+ }
30
+ else {
31
+ newX = newX % width;
32
+ }
33
+ if (newY < 0 ) {
34
+ newY = (height - (std::abs (newY) % height)) % height;
35
+ }
36
+ else {
37
+ newY = newY % height;
38
+ }
39
+ if (newX != midVertical-1 && newY != midHorizontal-1 ) {
40
+ counters[2 * (newY / midHorizontal) + newX / midVertical]++;
41
+ }
42
+ map[newY][newX]++;
43
+ }
44
+
45
+ return std::accumulate (counters.begin (), counters.end (), size_t {1 }, std::multiplies<>{});
46
+ }
47
+
48
+ [[nodiscard]] double EuclideanDistanceFromOrigin (double x, double y) noexcept
49
+ {
50
+ return std::sqrt (x * x + y * y);
51
+ }
52
+
53
+ [[nodiscard]] double calculateVariance (const std::vector<std::vector<int >>& matrix) noexcept
54
+ {
55
+ const size_t midVertical{(matrix[0 ].size () / 2 ) + 1 };
56
+ const size_t midHorizontal{(matrix.size () / 2 ) + 1 };
57
+
58
+ double positionCount{};
59
+ double meanDistance{};
60
+ for (size_t i = 0 ; i < matrix.size (); ++i) {
61
+ for (size_t j = 0 ; j < matrix[0 ].size (); ++j) {
62
+ positionCount += matrix[i][j] != 0 ;
63
+ meanDistance += matrix[i][j] * EuclideanDistanceFromOrigin (i, j);
64
+ }
65
+ }
66
+ meanDistance /= positionCount;
67
+
68
+ double variance{};
69
+ for (size_t i = 0 ; i < matrix.size (); ++i) {
70
+ for (size_t j = 0 ; j < matrix[0 ].size (); ++j) {
71
+ const auto d{EuclideanDistanceFromOrigin (i, j)};
72
+ variance += matrix[i][j] * (d - meanDistance) * (d - meanDistance);
73
+ }
74
+ }
75
+
76
+ return variance;
77
+ }
78
+
79
+
80
+ [[nodiscard]] size_t solveSecondPart (const std::vector<RobotInfo>& inputVec) {
81
+ constexpr size_t width{101 };
82
+ constexpr size_t height{103 };
83
+ std::vector<std::vector<int >> map (height, std::vector<int >(width));
84
+
85
+ std::unordered_map<double , size_t > varianceFreq;
86
+
87
+ double minVariance{std::numeric_limits<double >::max ()};
88
+ size_t minVarianceId{};
89
+
90
+ size_t iteration{};
91
+ while (++iteration < 10000 ) {
92
+ map.clear ();
93
+ map.resize (height, std::vector<int >(width));
94
+
95
+ for (const auto & robot : inputVec) {
96
+ int64_t newX{robot.position .x + robot.velocityX * iteration};
97
+ int64_t newY{robot.position .y + robot.velocityY * iteration};
98
+ if (newX < 0 ) {
99
+ newX = (width - (std::abs (newX) % width)) % width;
100
+ }
101
+ else {
102
+ newX = newX % width;
103
+ }
104
+ if (newY < 0 ) {
105
+ newY = (height - (std::abs (newY) % height)) % height;
106
+ }
107
+ else {
108
+ newY = newY % height;
109
+ }
110
+ map[newY][newX] = 1 ;
111
+ }
112
+ const double variance{calculateVariance (map)};
113
+ varianceFreq[variance]++;
114
+ if (variance < minVariance) {
115
+ minVariance = variance;
116
+ minVarianceId = iteration;
117
+ }
118
+ }
119
+
120
+ return minVarianceId;
121
+ }
122
+
123
+
124
+ [[nodiscard]] RobotInfo parseRobotInfo (const std::string& input) {
125
+ RobotInfo info;
126
+
127
+ // Define the regex pattern to match key-value pairs like "p=0,4" or "v=3,-3"
128
+ std::regex pattern (R"( (\w+)=(-?\d+),(-?\d+))" );
129
+ std::smatch matches;
130
+
131
+ // Use an iterator to find all matches in the input string
132
+ auto begin = std::sregex_iterator (input.begin (), input.end (), pattern);
133
+ auto end = std::sregex_iterator ();
134
+
135
+ for (auto it = begin; it != end; ++it) {
136
+ matches = *it;
137
+
138
+ // Extract key and coordinates
139
+ const std::string key = matches[1 ];
140
+ const int x{std::stoi (matches[2 ])};
141
+ const int y{std::stoi (matches[3 ])};
142
+
143
+ // Store the parsed values in the map
144
+ if (key == " p" ) {
145
+ info.position = Position{x, y};
146
+ }
147
+ else if (key == " v" ) {
148
+ info.velocityX = x;
149
+ info.velocityY = y;
150
+ }
151
+ else {
152
+ throw std::logic_error{" unknown input: " + input};
153
+ }
154
+ }
155
+ return info;
156
+ }
157
+
158
+ void printHelp ()
159
+ {
160
+ std::cerr << " \n Usage:\n "
161
+ << " The program requires 2 args: (part1, part2) and the path to the file."
162
+ << " \n For example, ./day7 part1 data/day7.txt" ;
163
+ }
164
+
165
+ int main (int argc, char * argv[])
166
+ {
167
+ if (argc != 3 ) {
168
+ printHelp ();
169
+ return 1 ;
170
+ }
171
+
172
+ std::string_view task{argv[1 ]};
173
+ if (task != " part1" && task != " part2" ) {
174
+ std::cerr << " \n first arg can be either `part1` or `part2`\n " ;
175
+ printHelp ();
176
+ return 1 ;
177
+ }
178
+
179
+ std::vector<RobotInfo> inputVec;
180
+ readInput (argv[2 ], std::back_inserter (inputVec), parseRobotInfo);
181
+
182
+ if (task == " part1" ) {
183
+ std::cout << solveFirstPart (inputVec);
184
+ }
185
+ else {
186
+ std::cout << solveSecondPart (inputVec);
187
+ }
188
+
189
+ return 0 ;
190
+ }
0 commit comments