// Solutions to the Advent Of Code 2024. // Copyright (C) 2025 Stefan Müller // // This program is free software: you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software // Foundation, either version 3 of the License, or (at your option) any later // version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along with // this program. If not, see . #include GardenGroups::GardenGroups(const int inputFileNameSuffix) : LinesSolver{ inputFileNameSuffix } { } const std::string GardenGroups::getPuzzleName() const { return "Garden Groups"; } const int GardenGroups::getPuzzleDay() const { return 12; } void GardenGroups::finish() { Grid isVisited{ lines.size(), lines[0].size() }; isVisited.fill(false); std::stack otherRegionsStack{}; otherRegionsStack.emplace(0, 0); while (!otherRegionsStack.empty()) { const Point2 position{ otherRegionsStack.top() }; otherRegionsStack.pop(); if (!isVisited.cell(position)) { traverseRegion(isVisited, otherRegionsStack, position); } } } void GardenGroups::traverseRegion(Grid& isVisited, std::stack& otherRegionsStack, const Point2& start) { const char plantType{ getCharAt(start) }; long long int area{ 0 }; long long int perimeter{ 0 }; long long int nCorners{ 0 }; std::stack regionStack{}; regionStack.push(start); while (!regionStack.empty()) { const Point2 position{ regionStack.top() }; regionStack.pop(); if (!isVisited.cell(position)) { isVisited.cell(position) = true; area++; Point2 previousNeighbor{ position + Point2::cardinalDirections.back() }; bool isPreviousNeighborSameRegion{ isInBounds(previousNeighbor) && getCharAt(previousNeighbor) == plantType }; for (const Point2& direction : Point2::cardinalDirections) { const Point2 neighbor{ position + direction }; const bool isNeighborSameRegion{ isInBounds(neighbor) && getCharAt(neighbor) == plantType }; if (isNeighborSameRegion) { if (!isVisited.cell(neighbor)) { regionStack.push(neighbor); } // Increases the corner count if two adjacent neighbors are both inside this region, but the // diagonal neighbor in between them is outside this region. if (isPreviousNeighborSameRegion) { const Point2 diagonalNeighbor{ previousNeighbor + direction }; if (!isInBounds(diagonalNeighbor) || getCharAt(diagonalNeighbor) != plantType) { nCorners++; } } } else { if (isInBounds(neighbor) && !isVisited.cell(neighbor)) { otherRegionsStack.push(neighbor); } perimeter++; // Increases the corner count if two adjacent neighbors are both outside this region. if (!isPreviousNeighborSameRegion) { nCorners++; } } previousNeighbor = neighbor; isPreviousNeighborSameRegion = isNeighborSameRegion; } } } part1 += area * perimeter; part2 += area * nCorners; }