-
Notifications
You must be signed in to change notification settings - Fork 0
/
run.hs
90 lines (72 loc) · 2.36 KB
/
run.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
{-# LANGUAGE TupleSections #-}
import Data.Bifunctor
import Data.List (sort)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Text.Megaparsec hiding (State, empty)
import Text.Megaparsec.Char
import Data.Void (Void)
unsafeRight (Right x) = x
type BotId = Int
type OutputId = Int
data Target = B BotId | O OutputId
type Logic = (HashMap BotId [Int], HashMap OutputId Int)
empty :: Logic
empty = (HashMap.empty, HashMap.empty)
num = read <$> some digitChar
insertBot :: Int -> BotId -> Logic -> Logic
insertBot val bid = first (HashMap.insertWith (++) bid [val])
insertOut :: Int -> OutputId -> Logic -> Logic
insertOut val oid = second (HashMap.insert oid val)
insertTarget :: Int -> Target -> Logic -> Logic
insertTarget val t =
case t of
O oid -> insertOut val oid
B bid -> insertBot val bid
insert val bid = Just . insertBot val bid
move :: BotId -> Target -> Target -> Logic -> Maybe Logic
move bid lowTo highTo logic = do
[low, high] <- sort <$> HashMap.lookup bid (fst logic)
pure . insertTarget low lowTo . insertTarget high highTo $ logic
type Inst = Logic -> Maybe Logic
insertP = insert <$> (string "value " *> num)
<*> (string " goes to bot " *> num)
moveP = move <$> (string "bot " *> num)
<*> (string " gives low to " *> targetP)
<*> (string " and high to " *> targetP)
targetP = O <$> (string "output " *> num)
<|> B <$> (string "bot " *> num)
inst :: Parsec Void String Inst
inst = insertP <|> moveP
parseAll = map unsafeRight .
map (parse inst "") . lines
eval :: [Inst] -> Logic
eval = snd . until (null . fst) eval' . (,empty)
where eval' :: ([Inst], Logic) -> ([Inst], Logic)
eval' (inst, l) = first reverse $ foldl step ([], l) inst
step :: ([Inst], Logic) -> Inst -> ([Inst], Logic)
step (rem, l) instr =
case instr l of
Just l' -> (rem, l')
Nothing -> (instr:rem, l)
part1 :: [Inst] -> BotId
part1 =
fst . head
. filter ((== [17, 61]) . snd)
. map (second sort)
. HashMap.toList
. fst
. eval
part2 :: [Inst] -> Int
part2 =
product
. map snd
. filter ((`elem` [0,1,2]) . fst)
. HashMap.toList
. snd
. eval
loeb x = fmap (\a -> a (loeb x)) x
main = do
input <- parseAll <$> getContents
print (part1 input)
print (part2 input)