import Text.Regex.Posix ((=~)) import Data.List main :: IO () main = do input <- readFile "input" let instructions = findAll "mul\\([0-9]+,[0-9]+\\)|do\\(\\)|don't\\(\\)" input let muls = filter (/= "do()") . stripDont $ instructions let pairs = map parseMul muls let total = sum (map (\(x,y) -> x*y) pairs) print total splitBy :: Eq a => [a] -> a -> ([a], [a]) splitBy xs sep = case elemIndex sep xs of Nothing -> (xs, []) Just i -> (take i xs, drop (i+1) xs) stripDont :: [String] -> [String] stripDont xs = let (start, temp) = splitBy xs "don't()" (_, end) = splitBy temp "do()" in if end == [] then start else (start ++ (stripDont end)) parseMul s = read (drop 3 s) :: (Int, Int) findAll rx s = case findFirst rx s of Nothing -> [] Just (match, rest) -> match:(findAll rx rest) findFirst :: String -> String -> Maybe (String, String) findFirst rx s = -- before, match, after, submatches case s =~ rx :: (String, String, String, [String]) of (_, "", _ ,_) -> Nothing (_, match, rest, _) -> Just (match, rest)