From 1c8b315fea2268de8cd9a1cd9170058df6b807d7 Mon Sep 17 00:00:00 2001 From: Amneesh Singh Date: Sun, 11 Dec 2022 22:00:09 +0530 Subject: [PATCH] day 11 Signed-off-by: Amneesh Singh --- day11.hs | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 day11.hs diff --git a/day11.hs b/day11.hs new file mode 100644 index 0000000..4022aa6 --- /dev/null +++ b/day11.hs @@ -0,0 +1,109 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ViewPatterns #-} + +import Data.Either (rights) +import Data.List (sortOn) +import Data.Map (Map) +import qualified Data.Map as M (elems, fromList, insert, keys, lookup, update) +import Data.Maybe (fromJust) +import Data.Ord (Down (Down)) +import Data.Text (Text) +import qualified Data.Text as T (empty, init, lines, stripSuffix, words) +import qualified Data.Text.Read as T (decimal, signed) +import Lib (readFile') +import Prelude hiding (round) + +-- again a slow program ;-; takes 410 ms when measured with `time` + +main :: IO () +main = do + input <- parse . T.lines <$> readFile' "day11.in" + putStr "Q1: " + print $ q 3 20 input + putStr "Q2: " + print $ q 1 10000 input + +data Monkey = Banana + { items :: [Int], + operation :: Int -> Int -> Int, + factor :: Int, + next :: (Int, Int), + iCount :: Int + } + +q :: Int -> Int -> Map Int Monkey -> Int +q d n = + product . take 2 + . sortOn Down + . map iCount + . M.elems + . (!! n) + . iterate (round d) + +round :: Int -> Map Int Monkey -> Map Int Monkey +round d monkeys = + foldl + ( \m k -> + let (Banana items op f (a, b) c) = fromJust $ M.lookup k m + in M.insert k (Banana [] op f (a, b) (c + length items)) $ + foldr + ( \x m -> + let worry = op x d `mod` divisor + in M.update + ( Just + . ( \(Banana items' op' f' n' c') -> + Banana (worry : items') op' f' n' c' + ) + ) + (if worry `mod` f == 0 then a else b) + m + ) + m + items + ) + monkeys + (M.keys monkeys) + where + divisor :: Int + divisor = foldr1 lcm (map factor $ M.elems monkeys) + +parse :: [Text] -> Map Int Monkey +parse = + M.fromList + . map + ( \( (parseMonkey -> n) + : (parseItems -> xs) + : (parseOp -> op) + : (parseTest -> (f, a, b)) + ) -> (n, Banana xs op f (a, b) 0) + ) + . sLines + where + parseMonkey :: Text -> Int + parseMonkey (T.words -> ["Monkey", T.decimal . T.init -> Right (n, "")]) = n + + parseItems :: Text -> [Int] + parseItems (T.words -> "Starting" : "items:" : xs) = + map (\(T.decimal -> Right (n, _)) -> n) xs + + parseOp :: Text -> (Int -> Int -> Int) + parseOp (T.words -> ["Operation:", "new", "=", e1, o, e2]) = + \x d -> div (parseO o (parseE x e1) (parseE x e2)) d + where + parseO o = if o == "+" then (+) else (*) + parseE x e = case T.decimal e of + Right (n, "") -> n + Left _ -> x + + parseTest :: [Text] -> (Int, Int, Int) + parseTest + [ T.words -> ["Test:", "divisible", "by", T.decimal -> Right (t, "")], + T.words -> ["If", "true:", "throw", "to", "monkey", T.decimal -> Right (a, "")], + T.words -> ["If", "false:", "throw", "to", "monkey", T.decimal -> Right (b, "")] + ] = (t, a, b) + + sLines :: [Text] -> [[Text]] + sLines [] = [] + sLines input = + let (cur, rest) = break (== T.empty) input + in cur : sLines (drop 1 rest)