module Day1 where import Data.Char import Data.Foldable (find) run :: IO () run = do calibrationLines <- parseInput part1 calibrationLines part2 calibrationLines part1 :: [String] -> IO () part1 calibrationLines = printAnswer 1 (answer id id calibrationLines) part2 :: [String] -> IO () part2 calibrationLines = printAnswer 2 (answer detectDigits detectReverseDigits calibrationLines) printAnswer :: Int -> Either String Int -> IO () printAnswer part (Left err) = putStrLn $ "Part " <> show part <> " Error: " <> err printAnswer part (Right ans) = putStrLn $ "Part " <> show part <> " Answer: " <> show ans answer :: (String -> String) -> (String -> String) -> [String] -> Either String Int answer preprocessorFirst preprocessorLast calibrationLines = sum <$> mapM (calibrationValue preprocessorFirst preprocessorLast) calibrationLines calibrationValue :: (String -> String) -> (String -> String) -> String -> Either String Int calibrationValue preprocessorFirst preprocessorLast line = let mFirstDigit = find isDigit $ preprocessorFirst line mLastDigit = find isDigit $ preprocessorLast $ reverse line in maybe (Left $ "No numbers in this line: " <> line) Right $ twoDigitNumber <$> mFirstDigit <*> mLastDigit {- ORMOLU_DISABLE -} detectDigits :: String -> String detectDigits [] = [] detectDigits ('z' : 'e' : 'r' : 'o' : rest) = '0' : detectDigits rest detectDigits ('o' : 'n' : 'e' : rest) = '1' : detectDigits rest detectDigits ('t' : 'w' : 'o' : rest) = '2' : detectDigits rest detectDigits ('t' : 'h' : 'r' : 'e' : 'e' : rest) = '3' : detectDigits rest detectDigits ('f' : 'o' : 'u' : 'r' : rest) = '4' : detectDigits rest detectDigits ('f' : 'i' : 'v' : 'e' : rest) = '5' : detectDigits rest detectDigits ('s' : 'i' : 'x' : rest) = '6' : detectDigits rest detectDigits ('s' : 'e' : 'v' : 'e' : 'n' : rest) = '7' : detectDigits rest detectDigits ('e' : 'i' : 'g' : 'h' : 't' : rest) = '8' : detectDigits rest detectDigits ('n' : 'i' : 'n' : 'e' : rest) = '9' : detectDigits rest detectDigits (x : rest) = x : detectDigits rest detectReverseDigits :: String -> String detectReverseDigits [] = [] detectReverseDigits ('0' : 'r' : 'e' : 'z' : rest) = '0' : detectReverseDigits rest detectReverseDigits ('e' : 'n' : 'o' : rest) = '1' : detectReverseDigits rest detectReverseDigits ('o' : 'w' : 't' : rest) = '2' : detectReverseDigits rest detectReverseDigits ('e' : 'e' : 'r' : 'h' : 't' : rest) = '3' : detectReverseDigits rest detectReverseDigits ('r' : 'u' : 'o' : 'f' : rest) = '4' : detectReverseDigits rest detectReverseDigits ('e' : 'v' : 'i' : 'f' : rest) = '5' : detectReverseDigits rest detectReverseDigits ('x' : 'i' : 's' : rest) = '6' : detectReverseDigits rest detectReverseDigits ('n' : 'e' : 'v' : 'e' : 's' : rest) = '7' : detectReverseDigits rest detectReverseDigits ('t' : 'h' : 'g' : 'i' : 'e' : rest) = '8' : detectReverseDigits rest detectReverseDigits ('e' : 'n' : 'i' : 'n' : rest) = '9' : detectReverseDigits rest detectReverseDigits (x : rest) = x : detectReverseDigits rest {- ORMOLU_ENABLE -} twoDigitNumber :: Char -> Char -> Int twoDigitNumber firstDigit lastDigit = 10 * digitToInt firstDigit + digitToInt lastDigit parseInput :: IO [String] parseInput = lines <$> getContents