|
| 1 | +{-# LANGUAGE TupleSections #-} |
| 2 | +{-# LANGUAGE ViewPatterns #-} |
| 3 | + |
| 4 | +import Control.Monad.Zip (mzip) |
| 5 | +import Data.List (singleton) |
| 6 | +import Data.List.Split (splitOn) |
| 7 | +import Data.Tree |
| 8 | + |
| 9 | +data Equation = Equation {result :: Int, terms :: [Int]} deriving (Show) |
| 10 | + |
| 11 | +instance Read Equation where |
| 12 | + readsPrec _ (splitOn ":" -> [lhs, rhs]) = |
| 13 | + let result = read lhs |
| 14 | + terms = map read $ words rhs |
| 15 | + in [(Equation {result = result, terms = terms}, "")] |
| 16 | + readsPrec _ _ = [] |
| 17 | + |
| 18 | +data Operator = Add | Multiply | Concat | Init deriving (Show) |
| 19 | + |
| 20 | +operators :: Tree Operator |
| 21 | +operators = unfoldTree (,[Add, Multiply, Concat]) Init |
| 22 | + |
| 23 | +toLayers :: [a] -> Tree a |
| 24 | +toLayers (x : xs) = unfoldTree f (x, xs) |
| 25 | + where |
| 26 | + f (current, []) = (current, []) |
| 27 | + f (current, next : rest) = (current, repeat (next, rest)) |
| 28 | + |
| 29 | +evalExpr :: Int -> Operator -> Int -> Int |
| 30 | +evalExpr _ Init a = a |
| 31 | +evalExpr a Add b = a + b |
| 32 | +evalExpr a Multiply b = a * b |
| 33 | +evalExpr a Concat b = a * o + b |
| 34 | + where |
| 35 | + o = head (dropWhile (b >=) [10 ^ x | x <- [0 ..]]) |
| 36 | + |
| 37 | +interimResults :: [Int] -> Tree Int |
| 38 | +interimResults terms = scanTree (uncurry . evalExpr) 0 (mzip operators (toLayers terms)) |
| 39 | + |
| 40 | +isSatisfyable :: Equation -> Bool |
| 41 | +isSatisfyable (Equation r ts) = elem r $ takeWhileTree (r >=) $ interimResults ts |
| 42 | + |
| 43 | +main = do |
| 44 | + contents <- readFile "input7.txt" |
| 45 | + let equations = (map read $ lines contents) :: [Equation] |
| 46 | + putStrLn "Part 2:" |
| 47 | + print $ sum $ map result $ filter isSatisfyable equations |
| 48 | + |
| 49 | +scanTree :: (b -> a -> b) -> b -> Tree a -> Tree b |
| 50 | +scanTree f s t = unfoldTree unfoldF (s, t) |
| 51 | + where |
| 52 | + unfoldF (acc, Node r sf) = (res, map (res,) sf) |
| 53 | + where |
| 54 | + res = f acc r |
| 55 | + |
| 56 | +takeWhileTree :: (a -> Bool) -> Tree a -> Tree a |
| 57 | +takeWhileTree p = head . unfoldForest unfoldF . singleton |
| 58 | + where |
| 59 | + unfoldF (Node r sf) = (r, filter (p . rootLabel) sf) |
0 commit comments