Advent of Code 2024, Day 12
Some more flood fill and recursive function shenanigans. Thankfully it was never close to not finishing in time.
Part of the AoC 2024 series
This is again a flood fill exercise with some curveball thrown in for good measure to check their perimeter. Nothing hard.
Spoilers
Part 1
Given a map with different plants (letters), find the distinct regions that are made up of fields where the same plant (letter) is grown and they touch on their sides. If they only touch diagonally, they donât count as one region.
Then count the length of the perimeter, and give each region a price thatâs calculated by multiplying its area with its perimeter.
Approach here is flood fill again: parse the input into a HashMap<Coordinate, String>
where the value is the letter of the plant being grown.
Then for each entry (Coordinate) in the map, start by looking at all four of its neighbours: if itâs not the same letter as the one we started on, it doesnât belong in the same region. Add the current coordinate to the visited HashSet
, then pass each of the valid coordinates to the same function, so it will be recursive. Bail if weâve visited that spot before.
What weâre left with if a bunch of regions which have a HashSet<Coordinate>
. To count the area, we use the .len()
method on the set, and weâre done. I made this into a method.
To get the perimeter I added a method that will visit each coordinates in a region exactly once, checks all 4 of their neighbours, and if those neighbour coordinates are not found in the region, adds +1 to the perimeter length.
Once we have these methods in place, the correct result is calling region.area() * region.perimeter()
for each region and adding the results together.
Part 2
The only complication here is that occasionally perimeter items need to be merged.
Way I solved it is I normalised everything to the left or down.
First for every plot of a region, I check its neighbours. If there isnât a neighbour that way, I add a directional fence tuple to a set that looks like this: HashSet<(Coordinate, Side>
. That allows me to store all sides separately for the same coordinate.
Then for every entry in that set I check which way the fence goes. If itâs either Up or Down, I find the leftmost plot that still has a fence the same way. I go one by one, so I know the fence will be unbroken. Once I found that, I add the leftmost coordinate and fence location to a visited set, so if I land on a different part of the same side I wonât double count it.
Then I check to the right one by one, and once I run out of plots, I add the leftmost plotâs coordinate, the way the fence is, and its length to a HashMap<(Coordinate, Side), length>
.
For Left and Right the process is exactly the same, except first I find the bottomâmost plot, then work my way up.
All thatâs left is to calculate the scores: multiple each regionâs area with its sides that we just calculated. We donât actually care how long those sides are.
After my âď¸âď¸ I can finally go to sleep.
Spoiler photo by Lucas Degenhardt on Unsplash