Another year, another Advent of Code! This day 1 was surprisingly tricky, due to a very uncharacteristic oversight by the Advent of Code team.

Part 1 was straightforward: filter each line to find the digits, combine the first and last digits into a new string, read that string.

part1 :: [String] -> Int
part1  = sum . (fmap getCalibration)

getCalibration :: String -> Int
getCalibration calibration = read [head digits, last digits]
  where digits = filter isDigit calibration

Part 2 was where things got complicated, mainly due to some imprecision in the problem specifications. There is an edge case that isn't revealed in the given examples, that caught out me (and many others it seems).

The input string oneighthas one and eight as overlapping words. It turns out, that central e should be included in both the words, so the found numbers should be 1 and 8.

I ended up writing the conversion as a fold over the tails of the input string, testing each prefix of each tail of the string for being a digit or a number word. If it was one of those, I add the corresponding digit to the fold's result; if not, it's skipped.

part2 :: [String] -> Int
part2 calibrations = sum $ fmap (getCalibration . replaceNums) calibrations

replaceNums :: String -> String
replaceNums haystack = reverse $ foldl' go "" $ tails haystack
  where go acc [] = acc
        go acc xs 
          | "one"   `isPrefixOf` xs = '1' : acc
          | "two"   `isPrefixOf` xs = '2' : acc
          | "three" `isPrefixOf` xs = '3' : acc
          | "four"  `isPrefixOf` xs = '4' : acc
          | "five"  `isPrefixOf` xs = '5' : acc
          | "six"   `isPrefixOf` xs = '6' : acc
          | "seven" `isPrefixOf` xs = '7' : acc
          | "eight" `isPrefixOf` xs = '8' : acc
          | "nine"  `isPrefixOf` xs = '9' : acc
          | isDigit (head xs) = (head xs) : acc
          | otherwise = acc

I did consider using something like a Map to store the data, but in the end thought it was just as simple to keep it explicit in the function.

Code

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