75 lines
2.2 KiB
Haskell
75 lines
2.2 KiB
Haskell
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))
|