{-# LANGUAGE OverloadedStrings #-} {-# OPTIONS_GHC -Wno-unused-do-bind #-} module Day1 where import Data.Semigroup import Data.Char import Data.String import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as Char8 import Data.Attoparsec.Lazy import Data.Attoparsec.ByteString.Char8 (letter_ascii) import Data.Either (fromRight) -- import Debug.Trace main :: IO () main = do day1input <- lines <$> readFile "inputs/day1.input" putStrLn "Part 1 result:" print $ part1 day1input putStrLn "Part 2 result:" print $ part2 day1input part1 :: [String] -> Sum Int part1 = foldMap go where go :: String -> Sum Int go = glueFirstLast . map (\c -> read [c]) . filter isNumber part2 :: [String] -> Sum Int part2 = foldMap (glueFirstLast . getNumbers) glueFirstLast :: [Int] -> Sum Int glueFirstLast xs = Sum $ 10 * head xs + last xs getNumbers :: String -> [Int] getNumbers = fromRight [] . parseOnly numberParser . fromString numberParser :: Parser [Int] numberParser = do s <- concat <$> (parseN `sepBy` letter_ascii) pure $ concatMap toInt s where parseN = many' . choice $ map string ["oneight","threeight","fiveight","sevenine","nineight","eightwo","eighthree","twone" ,"one","two","three","four","five","six","seven","eight","nine" , "1","2","3","4","5","6","7","8","9" ] toInt :: B.ByteString -> [Int] toInt "one" = [1] toInt "two" = [2] toInt "three" = [3] toInt "four" = [4] toInt "five" = [5] toInt "six" = [6] toInt "seven" = [7] toInt "eight" = [8] toInt "nine" = [9] toInt "oneight" = [1,8] toInt "threeight" = [3,8] toInt "fiveight" = [5,8] toInt "sevenine" = [7,9] toInt "nineight" = [9,8] toInt "eighthree" = [8,3] toInt "eightwo" = [8,2] toInt "twone" = [2,1] toInt ss = [read $ Char8.unpack ss]