Day1.hs (3156B)
1 module Day1 (solution) where 2 3 import Control.Monad (liftM, join) 4 import Data.List (sort) 5 6 import Utils (SolType(..), safeRead, liftMonadTuple, both, integerDiff) 7 8 input :: IO String 9 input = readFile "inputs/day1" 10 11 exampleInput :: String 12 exampleInput = join [ 13 "3 4\n", 14 "4 3\n", 15 "2 5\n", 16 "1 3\n", 17 "3 9\n", 18 "3 3\n" 19 ] 20 21 -- | Split an input string into two smaller strings on any whitespace. All 22 -- further whitespace is ignored 23 -- Example: 24 -- >>> splitWhitespace "3 4" 25 -- Just ("3","4") 26 -- >>> splitWhitespace "4 3" 27 -- Just ("4","3") 28 -- >>> splitWhitespace "2 5" 29 -- Just ("2","5") 30 -- >>> splitWhitespace "1 3" 31 -- Just ("1","3") 32 -- >>> splitWhitespace "3 9" 33 -- Just ("3","9") 34 -- >>> splitWhitespace "3 3" 35 -- Just ("3","3") 36 -- >>> splitWhitespace "agasdfadpc" 37 -- Nothing 38 -- >>> splitWhitespace "abcde fghi jk" 39 -- Just ("abcde","fghijk") 40 splitWhitespace :: String -> Maybe (String, String) 41 splitWhitespace = helper [] Nothing 42 where 43 helper :: String -> Maybe String -> String -> Maybe (String, String) 44 --helper lAcc rAcc str 45 helper l Nothing (' ':rest) = helper l (Just []) rest 46 helper l Nothing (c:rest) = helper (c:l) Nothing rest 47 helper l r (' ':rest) = helper l r rest 48 helper l (Just r) (c:rest) = helper l (Just (c:r)) rest 49 helper l r [] = do 50 rStr <- r 51 return (reverse l, reverse rStr) 52 53 -- | Parse the input into the two lists of integers 54 -- Example: 55 -- >>> parse exampleInput 56 -- Just ([3,4,2,1,3,3],[4,3,5,3,9,3]) 57 parse :: String -> Maybe ([Integer], [Integer]) 58 parse inputStr = do 59 let ls = lines inputStr 60 lrs <- mapM splitWhitespace ls 61 (l, r) <- liftM unzip $ mapM (liftMonadTuple . both safeRead) lrs 62 return (l, r) 63 64 -- | Solution to day 1 part 1 65 -- Example: 66 -- >>> liftM solution1 $ parse exampleInput 67 -- Just 11 68 solution1 :: ([Integer], [Integer]) -> Integer 69 solution1 (l, r) = helper 0 (sort l, sort r) 70 where 71 helper :: Integer -> ([Integer], [Integer]) -> Integer 72 helper n (x:xs, y:ys) = helper (n + integerDiff x y) (xs, ys) 73 helper n ([], _) = n 74 helper n (_, []) = n 75 76 -- | Return the number of times something appears in a list 77 -- Example: 78 -- >>> numInstances 3 [4,3,5,3,9,3] 79 -- 3 80 -- >>> numInstances 4 [4,3,5,3,9,3] 81 -- 1 82 -- >>> numInstances 2 [4,3,5,3,9,3] 83 -- 0 84 -- >>> numInstances 1 [4,3,5,3,9,3] 85 -- 0 86 numInstances :: Eq a => a -> [a] -> Integer 87 numInstances = helper 0 88 where 89 helper :: Eq a => Integer -> a -> [a] -> Integer 90 helper n x (el:rest) 91 | x == el = helper (n + 1) x rest 92 | otherwise = helper n x rest 93 helper n _ [] = n 94 95 -- | Solution to day 1 part 2 96 -- Example: 97 -- >>> liftM solution2 $ parse exampleInput 98 -- Just 31 99 solution2 :: ([Integer], [Integer]) -> Integer 100 solution2 = helper 0 101 where 102 helper :: Integer -> ([Integer], [Integer]) -> Integer 103 helper n (x:xs, ys) = helper (n + x * numInstances x ys) (xs, ys) 104 helper n ([], _) = n 105 106 solution :: IO (SolType, SolType) 107 solution = do 108 probStr <- input 109 let parsedLists = parse probStr 110 let sol1 = liftM (IntSol . solution1) parsedLists 111 let sol2 = liftM (IntSol . solution2) parsedLists 112 return $ (MaybeSol sol1, MaybeSol sol2)