Add solution for "Day 12: Garden Groups", part 2
This commit is contained in:
parent
f3682a46a9
commit
5b15e36bc5
10
README.md
10
README.md
|
@ -74,6 +74,16 @@ The algorithm starts at the trail ends (the `9`'s) and searches all options from
|
|||
|
||||
Since the order of the pebbles does not actually matter, we can simply blink from one line of pebbles to the next and count only cardinalities of each number in the current line.
|
||||
|
||||
### Day 12: Garden Groups
|
||||
|
||||
:mag_right: Puzzle: <https://adventofcode.com/2024/day/12>, :white_check_mark: Solver: [`GardenGroups.cpp`](src/GardenGroups.cpp)
|
||||
|
||||
The algorithm uses two stacks to flood-fill each garden region; one stack for all plots inside the region, and one stack to collect all other plots encountered during the flood-fill. Once a region has been traversed, it just pops the next plot from the latter stack. This gives us naturally the area of a region.
|
||||
|
||||
The perimeter of a region is the sum of neighbors for all plots encountered during the traversal, that are not in the same region, also counting neighbors outside the defined area. The number of sides of a region is equal to the number of corners of a region, which can also be counted per plot while doing the region traversal. A corner occurs for each pair of adjacent cardinal neighbors if they are either both outside of the current region, or if they are both inside the region and the diagonal neighbor in between them is not.
|
||||
|
||||
Adding up the products of area and perimeter, or area and corner count, per region gives us the solution.
|
||||
|
||||
## Thanks
|
||||
|
||||
* [Alexander Brouwer](https://github.com/Bromvlieg) for getting the project set up with CMake.
|
||||
|
|
|
@ -53,6 +53,7 @@ void GardenGroups::traverseRegion(Grid<bool>& isVisited, std::stack<Point2>& oth
|
|||
const char plantType{ getCharAt(start) };
|
||||
long long int area{ 0 };
|
||||
long long int perimeter{ 0 };
|
||||
long long int nCorners{ 0 };
|
||||
std::stack<Point2> regionStack{};
|
||||
regionStack.push(start);
|
||||
|
||||
|
@ -65,34 +66,54 @@ void GardenGroups::traverseRegion(Grid<bool>& isVisited, std::stack<Point2>& oth
|
|||
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 next{ position + direction };
|
||||
if (isInBounds(next))
|
||||
const Point2 neighbor{ position + direction };
|
||||
const bool isNeighborSameRegion{ isInBounds(neighbor) && getCharAt(neighbor) == plantType };
|
||||
|
||||
if (isNeighborSameRegion)
|
||||
{
|
||||
if (getCharAt(next) == plantType)
|
||||
if (!isVisited.cell(neighbor))
|
||||
{
|
||||
if (!isVisited.cell(next))
|
||||
{
|
||||
regionStack.push(next);
|
||||
regionStack.push(neighbor);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
// 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)
|
||||
{
|
||||
perimeter++;
|
||||
if (!isVisited.cell(next))
|
||||
const Point2 diagonalNeighbor{ previousNeighbor + direction };
|
||||
if (!isInBounds(diagonalNeighbor) || getCharAt(diagonalNeighbor) != plantType)
|
||||
{
|
||||
otherRegionsStack.push(next);
|
||||
nCorners++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
perimeter++;
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -182,19 +182,27 @@ TEST_CASE("[GardenGroupsTests]")
|
|||
TestContext test;
|
||||
SECTION("FullData")
|
||||
{
|
||||
test.run(std::make_unique<GardenGroups>(), 1477762, 0, test.getInputPaths());
|
||||
test.run(std::make_unique<GardenGroups>(), 1477762, 923480, test.getInputPaths());
|
||||
}
|
||||
SECTION("ExampleData")
|
||||
{
|
||||
test.run(std::make_unique<GardenGroups>(), 1930, 0, test.getExampleInputPaths());
|
||||
test.run(std::make_unique<GardenGroups>(), 1930, 1206, test.getExampleInputPaths());
|
||||
}
|
||||
SECTION("ExampleData2")
|
||||
{
|
||||
test.run(std::make_unique<GardenGroups>(2), 140, 0, test.getExampleInputPaths());
|
||||
test.run(std::make_unique<GardenGroups>(2), 140, 80, test.getExampleInputPaths());
|
||||
}
|
||||
SECTION("ExampleData3")
|
||||
{
|
||||
test.run(std::make_unique<GardenGroups>(3), 772, 0, test.getExampleInputPaths());
|
||||
test.run(std::make_unique<GardenGroups>(3), 772, 436, test.getExampleInputPaths());
|
||||
}
|
||||
SECTION("ExampleData4")
|
||||
{
|
||||
test.runPart2(std::make_unique<GardenGroups>(4), 236, test.getExampleInputPaths());
|
||||
}
|
||||
SECTION("ExampleData5")
|
||||
{
|
||||
test.runPart2(std::make_unique<GardenGroups>(5), 368, test.getExampleInputPaths());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue