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