Compare commits

...

3 commits

Author SHA1 Message Date
c9cec84910 Day 9 2025-12-18 22:05:34 +00:00
42d7f81e60 Day 8 2025-12-18 22:05:27 +00:00
cf51ce2dd1 Day8 2025-12-13 12:35:10 +00:00
6 changed files with 727 additions and 132 deletions

View file

@ -42,5 +42,6 @@ add_subdirectory(day5)
add_subdirectory(day6) add_subdirectory(day6)
add_subdirectory(day7) add_subdirectory(day7)
add_subdirectory(day8) add_subdirectory(day8)
add_subdirectory(day9)

View file

@ -1,174 +1,150 @@
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <cstddef>
#include <expected> #include <expected>
#include <format>
#include <fstream> #include <fstream>
#include <functional>
#include <iostream> #include <iostream>
#include <map> #include <numeric>
#include <print> #include <print>
#include <ranges> #include <ranges>
#include <string> #include <string>
#include <unordered_map> #include <string_view>
#include <utility>
#include <vector> #include <vector>
using Point = std::tuple<int, int, int>; // 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<int> parent;
int groups;
explicit DSU(size_t n) : parent(n), groups(static_cast<int>(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 ---
static auto getDistance(const Point &a, const Point &b) -> double { static auto getDistance(const Point &a, const Point &b) -> double {
return sqrt(pow(std::get<0>(a) - std::get<0>(b), 2) + pow(std::get<1>(a) - std::get<1>(b), 2) + // std::hypot is cleaner (C++17) and avoids manual pow/sqrt
pow(std::get<2>(a) - std::get<2>(b), 2)); // 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);
} }
static auto parseInput(const std::string &filename) -> std::expected<std::vector<Point>, std::string> { static auto parseInput(std::string_view filename) -> std::expected<std::vector<Point>, std::string> {
std::ifstream inputF{filename}; std::ifstream inputF{std::string(filename)};
if (!inputF) { if (!inputF) {
return std::unexpected{"Some file open error."}; return std::unexpected{"Could not open file."};
} }
std::vector<Point> pointVec{}; std::vector<Point> points;
std::string line;
std::string puzzleLine; while (std::getline(inputF, line)) {
while (std::getline(inputF, puzzleLine)) { if (line.empty()) {
if (!puzzleLine.empty()) { continue;
auto subParts = std::ranges::to<std::vector<std::string>>(std::views::split(puzzleLine, ',')); }
pointVec.emplace_back(std::stoi(subParts[0]), std::stoi(subParts[1]), std::stoi(subParts[2]));
// 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<std::vector<std::string>>();
if (parts.size() >= 3) {
points.emplace_back(std::stoi(parts[0]), std::stoi(parts[1]), std::stoi(parts[2]));
} }
} }
// std::println("pointList: {}", pointVec); return points;
return pointVec;
} }
static auto getCombinations(const std::vector<Point> &pointVec) -> std::vector<std::pair<Point, Point>> { static auto generateSortedEdges(const std::vector<Point> &points) -> std::vector<Edge> {
std::vector<std::pair<Point, Point>> result; std::vector<Edge> edges;
edges.reserve((points.size() * (points.size() - 1)) / 2);
result.reserve(pointVec.size() * pointVec.size()); // Standard triangular loop is still clearer/faster than range combinatorics here
for (size_t i = 0; i < points.size(); ++i) {
for (size_t i = 0; i < pointVec.size(); ++i) { for (size_t j = i + 1; j < points.size(); ++j) {
for (size_t j = i + 1; j < pointVec.size(); ++j) { edges.push_back(
result.emplace_back(pointVec[i], pointVec[j]); {.u = static_cast<int>(i), .v = static_cast<int>(j), .dist = getDistance(points[i], points[j])});
} }
} }
return std::move(result);
// Modern Sort with Projections
// Sorts by the 'dist' member automatically
std::ranges::sort(edges, {}, &Edge::dist);
return edges;
} }
static auto getDistances(const std::vector<Point> &pointVec) -> auto { // --- Main Logic ---
auto comparisonLamb = [](const std::pair<Point, Point> &pair1, const std::pair<Point, Point> &pair2) -> bool {
return getDistance(pair1.first, pair1.second) < getDistance(pair2.first, pair2.second);
};
std::map<std::pair<Point, Point>, double, decltype(comparisonLamb)> sortedMap(comparisonLamb);
auto combinations = getCombinations(pointVec); static auto solvePartTwo(const std::vector<Point> &points) -> long long {
for (const auto &combination : combinations) { auto edges = generateSortedEdges(points);
DSU dsu(points.size());
// std::println("Combinations: {}:{}", combination.first, combination.second); for (const auto &[u, v, dist] : edges) {
sortedMap[combination] = getDistance(combination.first, combination.second); // Try to unite the two points
} if (dsu.unite(u, v)) {
// If this connection reduced us to exactly 1 group, we are done!
return sortedMap; if (dsu.groups == 1) {
} std::println("Connected all points! Last edge: {} <-> {}", u, v);
return (long long)points[u].x * (long long)points[v].x;
static auto doTheThing(const std::vector<Point> &pointVec, int numberToTake) -> long long {
auto distanceMap = getDistances(pointVec);
std::map<Point, int> pointToCircuitMap{};
std::unordered_map<int, std::vector<Point>> 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);
std::println("circuitMap"); return -1; // Should not happen if graph is connected
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::vector<int>>();
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 { auto main() -> int {
auto testCase = parseInput("test_input"); // Usage of std::string_view literal
if (testCase) { auto puzzle = parseInput("puzzle_input");
auto testResult = doTheThing(*testCase, 10); if (!puzzle) {
std::println("P1 Testcase result: {}", testResult); std::println(stderr, "Error: {}", puzzle.error());
return 1;
// auto testResultP2 = treePartTwo(*testCase);
// std::println("P2 Testcase result: {}", testResultP2);
} else {
std::print("{}\n", testCase.error());
} }
auto realPuzzle = parseInput("puzzle_input"); std::println("Loaded {} points.", puzzle->size());
if (realPuzzle) {
// auto realResult = doTheThing(*realPuzzle, 1000);
// std::println("P1 Real result: {}", realResult);
auto realResultP2 = doTheThing(*realPuzzle, 1000); // Part 2 Logic
std::println("P2 Real result: {}", realResultP2); auto result = solvePartTwo(*puzzle);
} else { std::println("Part 2 Result: {}", result);
std::print("{}\n", realPuzzle.error());
}
return 0; return 0;
} }

2
day9/CMakeLists.txt Normal file
View file

@ -0,0 +1,2 @@
# Use top-level helper to add the target and copy input files
aoc_add_day(day9 "${CMAKE_CURRENT_SOURCE_DIR}" main.cpp)

112
day9/main.cpp Normal file
View file

@ -0,0 +1,112 @@
#include <algorithm>
#include <array>
#include <charconv>
#include <cstddef>
#include <expected>
#include <format>
#include <fstream>
#include <functional>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <mdspan>
#include <numeric>
#include <print>
#include <ranges>
#include <set>
#include <sstream>
#include <string>
#include <string_view>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
struct CoordinateHash {
auto operator()(const std::pair<long long, long long> &p) const -> std::size_t {
auto h1 = std::hash<long long>{}(p.first);
auto h2 = std::hash<long long>{}(p.second);
return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
}
};
using Coordinate = std::pair<int, int>;
static auto parseInput(std::string_view filename) -> std::expected<std::vector<Coordinate>, std::string> {
std::ifstream inputF{std::string(filename)};
if (!inputF) {
return std::unexpected{"Could not open file."};
}
std::vector<Coordinate> 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<std::vector<std::string>>();
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<Coordinate> &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;
}

496
day9/puzzle_input Normal file
View file

@ -0,0 +1,496 @@
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

8
day9/test_input Normal file
View file

@ -0,0 +1,8 @@
7,1
11,1
11,7
9,7
9,5
2,5
2,3
7,3