70 lines
3.4 KiB
Haskell
70 lines
3.4 KiB
Haskell
|
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
|