import Control.Monad.State.Strict import Data.List data Monkey = Monkey {items :: [Int], operation :: Int -> Int, test :: (Int, Int, Int), inspected :: Int} op :: String -> Int -> Int -> Int op "*" = (*) op "+" = (+) pread "old" old = old pread i _ = read i parseOp :: [String] -> Int -> Int parseOp [a,o,b] = \old -> op o (pread a old) (pread b old) parseDiv :: String -> Int parseDiv = read.last.words parse [_,i,o,d,t,f] = Monkey (read$"["++drop 18 i++"]")(parseOp $ words$drop 19 o) (parseDiv d, parseDiv t, parseDiv f) 0 instance Show Monkey where show (Monkey i o t ins) = "Monkey {items = " ++ show i ++ "} ("++ show ins ++")" instance Eq Monkey where m1 == m2 = inspected m1 == inspected m2 instance Ord Monkey where m1<=m2 = inspected m1 <= inspected m2 type MState = [Monkey] extract :: Int -> [a] -> ([a], a, [a]) extract i m|(f,(c:b))<-splitAt i m=(f,c,b) addTo :: Int -> Int -> State MState () addTo monkeyId item = do monkeys <- get let (f,monkey,b) = extract monkeyId monkeys let newMonkey = monkey {items = items monkey ++ [item]} put $ f ++ (newMonkey:b) step :: (Int -> Int) -> Int -> State MState () step op monkeyId = do monkeys <- get let monkey = monkeys !! monkeyId let newInspected = inspected monkey + length (items monkey) forM_ (items monkey) $ \item -> do let new = operation monkey item let unworried = op new let (divis, mtrue, mfalse) = test monkey if unworried `mod` divis == 0 then addTo mtrue unworried else addTo mfalse unworried let newMonkey = monkey {items = [], inspected = newInspected} m <- get let (f,c,b) = extract monkeyId m put (f ++ (newMonkey:b)) monkeyRound :: (Int -> Int) -> State MState () monkeyRound op = do l <- length<$>get forM_ [0..l-1] $ step op monkeyRounds i op = do forM_ [1..i] $ \_-> monkeyRound op maxdivis = product.map((\(a,b,c)->a).test) compute monkeys n op = product $ map inspected$ take 2$reverse$sort$execState (monkeyRounds n op) monkeys main = do monkeyFile <- map (parse.filter (/="")).groupBy(const (/="")).lines<$>readFile "day11long" print $ compute monkeyFile 20 (`div` 3) print $ compute monkeyFile 10000 (`mod` (maxdivis monkeyFile))