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