-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay11.hs
97 lines (84 loc) · 2.85 KB
/
Day11.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
{-# LANGUAGE FlexibleInstances #-}
module Day11
( part1
, part2
) where
import Data.List.Split (chunksOf, splitOn)
import Data.IntMap as M (IntMap, elems, fromList, insert, keys,
(!))
import Data.List (sortBy)
import Data.Sequence as S (Seq ((:<|), (:|>)), empty, fromList,
length, null)
data Monkey =
Monkey
{ items :: Seq Int
, operator :: Operation
, operand :: Int
, modulo :: Int
, true :: Int
, false :: Int
, count :: Int
}
type Operation = (Int -> Int -> Int)
instance (Eq Operation) where
a == b = a 1 2 == b 1 2
--instance (Show Operation) where
-- show op
-- | op == (*) = "*"
-- | op == (+) = "+"
-- | op == (^) = "^"
-- | otherwise = "undefined"
parseMonkey :: [String] -> (Int, Monkey)
parseMonkey (num:it:operation:mod:true:false:_) =
(nm, Monkey items operator operand modulo success fail 0)
where
end = last . words
nm = read . filter (/= ':') . end $ num
items = S.fromList . map (read . filter (/= ',')) . drop 2 . words $ it
(operator, operand)
| (op == "*") && (ope == "old") = ((^), 2)
| op == "*" = ((*), read ope)
| op == "+" = ((+), read ope)
where
(op:ope:_) = drop 4 . words $ operation
modulo = read . end $ mod
success = read . end $ true
fail = read . end $ false
monkeyTurn :: (Int -> Int) -> IntMap Monkey -> Int -> IntMap Monkey
monkeyTurn worryOp monkeys t = process seq monkeys
where
monkey = monkeys ! t
seq = items monkey
process curSeq dict
| S.null curSeq =
insert
t
monkey {items = empty, count = count monkey + S.length seq}
dict
| mod itemWorry (modulo monkey) == 0 =
process is $ insert tmi tm {items = items tm :|> itemWorry} dict
| otherwise =
process is $ insert fmi fm {items = items fm :|> itemWorry} dict
where
(i :<| is) = curSeq
itemWorry = worryOp $ operator monkey i $ operand monkey
tmi = true monkey
tm = dict ! tmi
fmi = false monkey
fm = dict ! fmi
doTurn :: (Int -> Int) -> IntMap Monkey -> IntMap Monkey
doTurn worryOp monkeys = foldl (monkeyTurn worryOp) monkeys . keys $ monkeys
monkeyBusiness :: Int -> (Int -> Int) -> IntMap Monkey -> Int
monkeyBusiness numTurns worryOp =
product .
take 2 .
sortBy (flip compare) .
map count . elems . last . take (numTurns + 1) . iterate (doTurn worryOp)
monkeys = M.fromList . map parseMonkey . chunksOf 7 . lines
part1 :: Bool -> String -> String
part1 _ = show . monkeyBusiness 20 (`div` 3) . monkeys
part2 :: Bool -> String -> String
part2 _ input = show . monkeyBusiness 10000 (`mod` modOp) $ m
where
m = monkeys input
modOp = product . map modulo . elems $ m