Advent of Code 2024 day 25

After the struggle of day 24, the final day 25 puzzle was a gentle relief.

A Schematic is either a Lock or a Key. Both have a list of heights.

data Schematic = Lock [Int] | Key [Int]
  deriving (Show, Eq, Ord)

I read the input by splitting it into lines, splitting it into schematics on blank lines, making the schematics, then splitting into locks and keys.

makeSchematics :: String -> ([Schematic], [Schematic])
makeSchematics = partition isLock . fmap makeSchematic . splitOn [""] . lines
  where isLock (Lock _) = True
        isLock _ = False

makeSchematic :: [String] -> Schematic
makeSchematic ss
  | isKeySchematic ss = Key $ heightsOf ss
  | isLockSchematic ss = Lock $ heightsOf ss
  | otherwise = error "Invalid schematic"

isKeySchematic, isLockSchematic :: [String] -> Bool
isKeySchematic  [a,_,_,_,_,_,b] = a == "....." && b == "#####"
isLockSchematic [a,_,_,_,_,_,b] = a == "#####" && b == "....."

heightsOf :: [String] -> [Int]
heightsOf = fmap ((-1 +) . length . filter (== '#')) . transpose

That converts the input into the list-of-heights form given in the puzzle description.

A lock and key are compatible if all the matching heights sum to less than or equal to five. A list comprehension finds all possible pairs of lock and key, filtered by compatibility.

part1 :: [Schematic] -> [Schematic] -> Int
part1 locks keys = length [(l, k) | l <- locks, k <- keys, compatible l k]

compatible :: Schematic -> Schematic -> Bool
compatible (Lock ls) (Key ks) = all (<= 5) $ zipWith (+) ls ks

And that's the end of the Advent of Code for another year!

500 stars

Code

You can get the code from my locally-hosted Git repo, or from Codeberg.