diff --git a/CMakeLists.txt b/CMakeLists.txt index c2e71ac..c5dcae0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,5 @@ add_subdirectory(day5) add_subdirectory(day6) add_subdirectory(day7) add_subdirectory(day8) -add_subdirectory(day9) diff --git a/day8/main.cpp b/day8/main.cpp index d81e7c6..b57022d 100644 --- a/day8/main.cpp +++ b/day8/main.cpp @@ -1,150 +1,174 @@ #include #include +#include #include +#include #include +#include #include -#include +#include #include #include #include -#include +#include +#include #include -// Use a simple struct for clarity -struct Point { - int x, y, z; - // Default spaceship operator for easy comparisons if needed - auto operator<=>(const Point &) const = default; -}; - -struct Edge { - int u; // Index of first point - int v; // Index of second point - double dist; -}; - -// --- Modern Union-Find (DSU) Implementation --- -struct DSU { - std::vector parent; - int groups; - - explicit DSU(size_t n) : parent(n), groups(static_cast(n)) { - // Fill with 0, 1, 2, ..., n-1 - std::iota(parent.begin(), parent.end(), 0); - } - - // Find with Path Compression - // Returns the representative ID of the set containing i - auto find(int i) -> int { - if (parent[i] == i) { - return i; - } - return parent[i] = find(parent[i]); - } - - // Unite two sets. Returns true if they were different sets. - auto unite(int i, int j) -> bool { - int root_i = find(i); - int root_j = find(j); - - if (root_i != root_j) { - parent[root_i] = root_j; // Link roots - groups--; - return true; - } - return false; - } -}; - -// --- Helper Functions --- +using Point = std::tuple; static auto getDistance(const Point &a, const Point &b) -> double { - // std::hypot is cleaner (C++17) and avoids manual pow/sqrt - // For 3D: hypot(x, y, z) is C++17 specific overload - return std::hypot(a.x - b.x, a.y - b.y, a.z - b.z); + return sqrt(pow(std::get<0>(a) - std::get<0>(b), 2) + pow(std::get<1>(a) - std::get<1>(b), 2) + + pow(std::get<2>(a) - std::get<2>(b), 2)); } -static auto parseInput(std::string_view filename) -> std::expected, std::string> { - std::ifstream inputF{std::string(filename)}; +static auto parseInput(const std::string &filename) -> std::expected, std::string> { + std::ifstream inputF{filename}; + if (!inputF) { - return std::unexpected{"Could not open file."}; + return std::unexpected{"Some file open error."}; } - std::vector points; - std::string line; + std::vector pointVec{}; - while (std::getline(inputF, line)) { - if (line.empty()) { - continue; - } - - // Modern splitting and parsing - auto parts = line | std::views::split(',') | std::views::transform([](auto &&rng) -> auto { - // Convert range to string for stoi (C++23 common_range fix) - return std::string(rng.begin(), rng.end()); - }) | - std::ranges::to>(); - - if (parts.size() >= 3) { - points.emplace_back(std::stoi(parts[0]), std::stoi(parts[1]), std::stoi(parts[2])); + std::string puzzleLine; + while (std::getline(inputF, puzzleLine)) { + if (!puzzleLine.empty()) { + auto subParts = std::ranges::to>(std::views::split(puzzleLine, ',')); + pointVec.emplace_back(std::stoi(subParts[0]), std::stoi(subParts[1]), std::stoi(subParts[2])); } } - return points; + // std::println("pointList: {}", pointVec); + return pointVec; } -static auto generateSortedEdges(const std::vector &points) -> std::vector { - std::vector edges; - edges.reserve((points.size() * (points.size() - 1)) / 2); +static auto getCombinations(const std::vector &pointVec) -> std::vector> { + std::vector> result; - // Standard triangular loop is still clearer/faster than range combinatorics here - for (size_t i = 0; i < points.size(); ++i) { - for (size_t j = i + 1; j < points.size(); ++j) { - edges.push_back( - {.u = static_cast(i), .v = static_cast(j), .dist = getDistance(points[i], points[j])}); + result.reserve(pointVec.size() * pointVec.size()); + + for (size_t i = 0; i < pointVec.size(); ++i) { + for (size_t j = i + 1; j < pointVec.size(); ++j) { + result.emplace_back(pointVec[i], pointVec[j]); } } - - // Modern Sort with Projections - // Sorts by the 'dist' member automatically - std::ranges::sort(edges, {}, &Edge::dist); - - return edges; + return std::move(result); } -// --- Main Logic --- +static auto getDistances(const std::vector &pointVec) -> auto { + auto comparisonLamb = [](const std::pair &pair1, const std::pair &pair2) -> bool { + return getDistance(pair1.first, pair1.second) < getDistance(pair2.first, pair2.second); + }; + std::map, double, decltype(comparisonLamb)> sortedMap(comparisonLamb); -static auto solvePartTwo(const std::vector &points) -> long long { - auto edges = generateSortedEdges(points); - DSU dsu(points.size()); + auto combinations = getCombinations(pointVec); + for (const auto &combination : combinations) { - for (const auto &[u, v, dist] : edges) { - // Try to unite the two points - if (dsu.unite(u, v)) { - // If this connection reduced us to exactly 1 group, we are done! - if (dsu.groups == 1) { - std::println("Connected all points! Last edge: {} <-> {}", u, v); - return (long long)points[u].x * (long long)points[v].x; + // std::println("Combinations: {}:{}", combination.first, combination.second); + sortedMap[combination] = getDistance(combination.first, combination.second); + } + + return sortedMap; +} + +static auto doTheThing(const std::vector &pointVec, int numberToTake) -> long long { + auto distanceMap = getDistances(pointVec); + std::map pointToCircuitMap{}; + std::unordered_map> circuitMap; + int currentCircuit = 0; + for (const auto &[combination, distance] : distanceMap) { + const auto &[left, right] = combination; + // std::println("DistanceMap: {}:{} = {}", left, right, distance); + + if (pointToCircuitMap.contains(left) && pointToCircuitMap.contains(right)) { + int leftCircuit = pointToCircuitMap[left]; + int rightCircuit = pointToCircuitMap[right]; + // std::println("Left circuit: {}. Right circuit: {}", leftCircuit, rightCircuit); + if (leftCircuit != rightCircuit) { + std::println("Merge: {} to {}", left, right); + + for (const auto &rightCircuitPoint : circuitMap[rightCircuit]) { + pointToCircuitMap[rightCircuitPoint] = leftCircuit; + } + circuitMap[leftCircuit].append_range(circuitMap[rightCircuit]); + circuitMap.erase(rightCircuit); + + // std::println("mergesize: {}", circuitMap[leftCircuit].size()); + if (circuitMap[leftCircuit].size() >= pointVec.size()) { + + return (long long)std::get<0>(left) * (long long)std::get<0>(right); + } } + } else if (pointToCircuitMap.contains(left)) { + int leftCircuit = pointToCircuitMap[left]; + // std::println("Only left exists: {} to {}", left, right); + pointToCircuitMap[right] = pointToCircuitMap[left]; + + circuitMap[leftCircuit].push_back(right); + // std::println("leftsize: {}", circuitMap[leftCircuit].size()); + if (circuitMap[leftCircuit].size() >= pointVec.size()) { + + return (long long)std::get<0>(left) * (long long)std::get<0>(right); + } + } else if (pointToCircuitMap.contains(right)) { + int rightCircuit = pointToCircuitMap[right]; + // std::println("Only right exists: {} to {}", left, right); + pointToCircuitMap[left] = pointToCircuitMap[right]; + + circuitMap[rightCircuit].push_back(left); + // std::println("rightsize: {}", circuitMap[rightCircuit].size()); + if (circuitMap[rightCircuit].size() >= pointVec.size()) { + + return (long long)std::get<0>(left) * (long long)std::get<0>(right); + } + } else { + currentCircuit++; + pointToCircuitMap[left] = currentCircuit; + pointToCircuitMap[right] = currentCircuit; + + circuitMap[currentCircuit].push_back(left); + circuitMap[currentCircuit].push_back(right); } } + // std::println("pointToCircuitMap: {}", pointToCircuitMap); - return -1; // Should not happen if graph is connected + std::println("circuitMap"); + for (const auto &[circuit, pointsInCircuit] : circuitMap) { + + std::println("{} : {}", circuit, pointsInCircuit); + } + + auto sizesOfLists = circuitMap | std::views::transform([](const auto &kvp) -> int { return kvp.second.size(); }) | + std::ranges::to>(); + std::ranges::sort(sizesOfLists, std::greater{}); + auto threeLargest = std::ranges::fold_left(sizesOfLists | std::views::take(3), 1, std::multiplies{}); + + // std::println("{}", threeLargest); + return threeLargest; } auto main() -> int { - // Usage of std::string_view literal - auto puzzle = parseInput("puzzle_input"); + auto testCase = parseInput("test_input"); + if (testCase) { - if (!puzzle) { - std::println(stderr, "Error: {}", puzzle.error()); - return 1; + auto testResult = doTheThing(*testCase, 10); + std::println("P1 Testcase result: {}", testResult); + + // auto testResultP2 = treePartTwo(*testCase); + // std::println("P2 Testcase result: {}", testResultP2); + } else { + std::print("{}\n", testCase.error()); } - std::println("Loaded {} points.", puzzle->size()); + auto realPuzzle = parseInput("puzzle_input"); + if (realPuzzle) { + // auto realResult = doTheThing(*realPuzzle, 1000); + // std::println("P1 Real result: {}", realResult); - // Part 2 Logic - auto result = solvePartTwo(*puzzle); - std::println("Part 2 Result: {}", result); + auto realResultP2 = doTheThing(*realPuzzle, 1000); + std::println("P2 Real result: {}", realResultP2); + } else { + std::print("{}\n", realPuzzle.error()); + } return 0; -} \ No newline at end of file +} diff --git a/day9/CMakeLists.txt b/day9/CMakeLists.txt deleted file mode 100644 index bee3402..0000000 --- a/day9/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ - # Use top-level helper to add the target and copy input files - aoc_add_day(day9 "${CMAKE_CURRENT_SOURCE_DIR}" main.cpp) \ No newline at end of file diff --git a/day9/main.cpp b/day9/main.cpp deleted file mode 100644 index d092c2c..0000000 --- a/day9/main.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct CoordinateHash { - auto operator()(const std::pair &p) const -> std::size_t { - - auto h1 = std::hash{}(p.first); - auto h2 = std::hash{}(p.second); - - return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2)); - } -}; - -using Coordinate = std::pair; - -static auto parseInput(std::string_view filename) -> std::expected, std::string> { - std::ifstream inputF{std::string(filename)}; - if (!inputF) { - return std::unexpected{"Could not open file."}; - } - - std::vector coordinates; - std::string line; - - while (std::getline(inputF, line)) { - if (line.empty()) { - continue; - } - - auto parts = line | std::views::split(',') | - std::views::transform([](auto &&rng) -> auto { return std::string(rng.begin(), rng.end()); }) | - std::ranges::to>(); - - if (parts.size() >= 2) { - coordinates.emplace_back(std::stoi(parts[0]), std::stoi(parts[1])); - } - } - return coordinates; -} - -static auto getArea(const Coordinate &left, const Coordinate &right) -> long long { - long long leftPart = std::abs(left.first - right.first) + 1; - long long rightPart = std::abs(left.second - right.second) + 1; - // std::print("{:2} * {:2} ", leftPart, rightPart); - return leftPart * rightPart; -} - -static auto solvePartOne(std::vector &coordinates) -> long long { - long long maxArea{}; - for (size_t i = 0; i < coordinates.size(); ++i) { - for (size_t j = i + 1; j < coordinates.size(); ++j) { - long long area = getArea(coordinates[i], coordinates[j]); - maxArea = std::max(area, maxArea); - // std::println("= {:2}; area of {} and {}", area, coordinates[i], coordinates[j]); - } - } - - return maxArea; -} - -auto main() -> int { - auto test = parseInput("test_input"); - - if (!test) { - std::println(stderr, "Error: {}", test.error()); - return 1; - } - - std::println("Test: Loaded {} points.", test->size()); - - auto testResult = solvePartOne(*test); - std::println("Test: Max Area: {}.", testResult); - - auto puzzle = parseInput("puzzle_input"); - - if (!puzzle) { - std::println(stderr, "Error: {}", puzzle.error()); - return 1; - } - - std::println("Puzzle: Loaded {} points.", puzzle->size()); - auto puzzleResult = solvePartOne(*puzzle); - std::println("Puzzle: Max Area: {}.", puzzleResult); - - // // Part 2 Logic - // auto result = solvePartTwo(*puzzle); - // std::println("Part 2 Result: {}", result); - - return 0; -} \ No newline at end of file diff --git a/day9/puzzle_input b/day9/puzzle_input deleted file mode 100644 index 8dcddfd..0000000 --- a/day9/puzzle_input +++ /dev/null @@ -1,496 +0,0 @@ -98154,50433 -98154,51659 -98318,51659 -98318,52839 -97531,52839 -97531,54072 -97795,54072 -97795,55273 -97599,55273 -97599,56438 -97163,56438 -97163,57630 -96985,57630 -96985,58862 -97008,58862 -97008,60001 -96540,60001 -96540,61238 -96525,61238 -96525,62389 -96136,62389 -96136,63729 -96399,63729 -96399,64863 -95924,64863 -95924,66096 -95742,66096 -95742,67229 -95265,67229 -95265,68026 -93975,68026 -93975,69483 -94298,69483 -94298,70437 -93447,70437 -93447,71702 -93255,71702 -93255,72471 -92092,72471 -92092,73807 -91997,73807 -91997,74541 -90844,74541 -90844,75747 -90491,75747 -90491,76890 -90014,76890 -90014,77857 -89265,77857 -89265,78572 -88186,78572 -88186,79561 -87489,79561 -87489,80961 -87282,80961 -87282,81285 -85786,81285 -85786,82279 -85089,82279 -85089,83598 -84715,83598 -84715,84056 -83449,84056 -83449,85206 -82869,85206 -82869,85762 -81730,85762 -81730,86992 -81183,86992 -81183,87726 -80201,87726 -80201,88040 -78902,88040 -78902,89210 -78253,89210 -78253,89823 -77189,89823 -77189,90009 -75855,90009 -75855,90815 -74933,90815 -74933,91606 -73991,91606 -73991,92411 -73044,92411 -73044,92934 -71938,92934 -71938,93433 -70822,93433 -70822,93648 -69581,93648 -69581,94314 -68546,94314 -68546,95024 -67517,95024 -67517,94716 -66105,94716 -66105,95285 -65025,95285 -65025,96388 -64097,96388 -64097,96208 -62773,96208 -62773,96508 -61596,96508 -61596,96717 -60399,96717 -60399,96734 -59166,96734 -59166,97217 -58025,97217 -58025,97725 -56872,97725 -56872,97536 -55620,97536 -55620,97385 -54388,97385 -54388,97698 -53201,97698 -53201,97956 -51999,97956 -51999,98476 -50792,98476 -50792,97657 -49571,97657 -49571,97890 -48355,97890 -48355,98145 -47124,98145 -47124,98316 -45883,98316 -45883,97952 -44687,97952 -44687,97958 -43453,97958 -43453,97033 -42361,97033 -42361,96816 -41173,96816 -41173,97033 -39892,97033 -39892,96956 -38657,96956 -38657,96441 -37528,96441 -37528,96130 -36350,96130 -36350,95671 -35217,95671 -35217,95273 -34069,95273 -34069,95070 -32845,95070 -32845,94644 -31699,94644 -31699,93613 -30817,93613 -30817,93489 -29542,93489 -29542,93176 -28337,93176 -28337,92481 -27321,92481 -27321,91694 -26364,91694 -26364,90870 -25443,90870 -25443,90230 -24418,90230 -24418,89472 -23473,89472 -23473,88942 -22372,88942 -22372,88622 -21100,88622 -21100,87565 -20378,87565 -20378,86615 -19591,86615 -19591,86172 -18377,86172 -18377,85663 -17192,85663 -17192,84787 -16331,84787 -16331,83324 -16070,83324 -16070,82800 -14866,82800 -14866,82182 -13727,82182 -13727,80646 -13644,80646 -13644,80193 -12282,80193 -12282,79304 -11429,79304 -11429,78018 -11116,78018 -11116,77212 -10142,77212 -10142,75913 -9901,75913 -9901,74888 -9258,74888 -9258,74205 -8022,74205 -8022,73085 -7511,73085 -7511,71792 -7349,71792 -7349,70816 -6580,70816 -6580,69681 -6128,69681 -6128,68714 -5284,68714 -5284,67466 -5106,67466 -5106,66359 -4578,66359 -4578,65036 -4680,65036 -4680,63974 -4016,63974 -4016,62754 -3859,62754 -3859,61611 -3430,61611 -3430,60462 -2997,60462 -2997,59180 -3198,59180 -3198,57968 -3115,57968 -3115,56786 -2871,56786 -2871,55659 -2129,55659 -2129,54386 -2631,54386 -2631,53203 -2260,53203 -2260,51991 -2244,51991 -2244,50781 -2169,50781 -2169,50401 -94699,50401 -94699,48346 -1840,48346 -1840,47122 -1834,47122 -1834,45904 -1930,45904 -1930,44738 -2511,44738 -2511,43572 -2915,43572 -2915,42343 -2857,42343 -2857,41166 -3146,41166 -3146,39955 -3257,39955 -3257,38776 -3536,38776 -3536,37554 -3652,37554 -3652,36292 -3674,36292 -3674,35141 -4091,35141 -4091,33976 -4464,33976 -4464,32898 -5069,32898 -5069,31972 -6021,31972 -6021,30493 -5649,30493 -5649,29455 -6326,29455 -6326,28642 -7432,28642 -7432,27428 -7720,27428 -7720,26421 -8405,26421 -8405,25199 -8722,25199 -8722,24020 -9143,24020 -9143,23327 -10310,23327 -10310,21943 -10453,21943 -10453,21244 -11568,21244 -11568,20019 -11979,20019 -11979,19219 -12936,19219 -12936,18221 -13648,18221 -13648,17813 -15012,17813 -15012,16324 -15205,16324 -15205,16070 -16674,16070 -16674,14784 -17123,14784 -17123,14187 -18224,14187 -18224,13164 -18948,13164 -18948,12901 -20301,12901 -20301,12140 -21235,12140 -21235,10741 -21711,10741 -21711,10344 -22925,10344 -22925,10007 -24155,10007 -24155,9447 -25226,9447 -25226,8483 -26060,8483 -26060,8154 -27263,8154 -27263,7684 -28378,7684 -28378,6350 -29073,6350 -29073,6326 -30407,6326 -30407,6127 -31638,6127 -31638,4808 -32417,4808 -32417,5034 -33804,5034 -33804,4750 -34986,4750 -34986,4343 -36124,4343 -36124,3377 -37112,3377 -37112,3398 -38380,3398 -38380,3461 -39640,3461 -39640,3182 -40816,3182 -40816,2907 -41995,2907 -41995,2161 -43111,2161 -43111,2019 -44327,2019 -44327,2137 -45567,2137 -45567,2347 -46801,2347 -46801,2084 -48001,2084 -48001,1828 -49212,1828 -49212,2439 -50427,2439 -50427,2250 -51639,2250 -51639,2565 -52833,2565 -52833,2148 -54077,2148 -54077,2164 -55299,2164 -55299,2738 -56451,2738 -56451,2802 -57665,2802 -57665,3238 -58815,3238 -58815,2830 -60136,2830 -60136,3636 -61199,3636 -61199,3429 -62505,3429 -62505,3635 -63718,3635 -63718,4523 -64718,4523 -64718,5061 -65813,5061 -65813,5459 -66953,5459 -66953,5293 -68325,5293 -68325,6415 -69169,6415 -69169,6668 -70383,6668 -70383,6681 -71733,6681 -71733,7882 -72484,7882 -72484,7927 -73849,7927 -73849,8994 -74637,8994 -74637,9180 -75955,9180 -75955,10353 -76643,10353 -76643,10757 -77840,10757 -77840,11923 -78490,11923 -78490,12448 -79611,12448 -79611,13185 -80573,13185 -80573,13529 -81882,13529 -81882,14572 -82591,14572 -82591,15742 -83155,15742 -83155,16606 -83999,16606 -83999,17071 -85270,17071 -85270,18173 -85870,18173 -85870,19222 -86510,19222 -86510,20214 -87207,20214 -87207,21071 -88074,21071 -88074,22170 -88622,22170 -88622,22934 -89641,22934 -89641,23738 -90637,23738 -90637,24863 -91147,24863 -91147,25941 -91723,25941 -91723,26996 -92336,26996 -92336,28213 -92638,28213 -92638,29042 -93713,29042 -93713,30301 -93909,30301 -93909,31451 -94317,31451 -94317,32685 -94502,32685 -94502,33573 -95609,33573 -95609,34821 -95747,34821 -95747,36122 -95663,36122 -95663,37280 -96014,37280 -96014,38330 -96801,38330 -96801,39562 -96891,39562 -96891,40803 -96883,40803 -96883,42002 -97055,42002 -97055,43148 -97578,43148 -97578,44409 -97285,44409 -97285,45554 -97999,45554 -97999,46811 -97513,46811 -97513,48015 -97582,48015 -97582,49215 -98001,49215 -98001,50433 diff --git a/day9/test_input b/day9/test_input deleted file mode 100644 index 7fb70de..0000000 --- a/day9/test_input +++ /dev/null @@ -1,8 +0,0 @@ -7,1 -11,1 -11,7 -9,7 -9,5 -2,5 -2,3 -7,3 \ No newline at end of file