109
day11.hs
Normal file
109
day11.hs
Normal file
@@ -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)
|
Reference in New Issue
Block a user