module Part1 where import Commons import Data.Map (insert, foldr, (!), notMember) applyModule :: Modules -> String -> Bool -> String -> (String, [String], Bool, Modules, Int, Int) applyModule modules source p n | notMember n modules = (n, [], True, modules, 0, 0) | otherwise = let m = modules ! n in case m of Broadcaster o -> (n, o, p, modules, if not p then length o else 0, if p then length o else 0) FlipFlop s o -> if not p then let newFF = FlipFlop {state = not s, outputs = o} in (n, o, not s, insert n newFF modules, if s then length o else 0, if not s then length o else 0) else (n, [], s, modules, 0, 0) Conjonction i o -> let newC = Conjonction {inputs = insert source p i, outputs = o} state = Data.Map.foldr (&&) True $ inputs newC in if state then (n, o, False, insert n newC modules, length o, 0) else (n, o, True, insert n newC modules, 0, length o) applyModules :: Modules -> String -> Bool -> [String] -> ([(String, [String], Bool)], Modules, Int, Int) applyModules modules _ _ [] = ([], modules, 0, 0) applyModules modules source p (h: t) = let (newS, outputs, newP, newModules, low, high) = applyModule modules source p h (result, newNewModules, newLow, newHigh) = applyModules newModules source p t in ((newS, outputs, newP): result, newNewModules, low + newLow, high + newHigh) applySteps :: Modules -> [(String, [String], Bool)] -> (Modules, Int, Int) applySteps modules [] = (modules, 0, 0) applySteps modules ((source, names, pulse): t) = let (result, newModules, low, high) = applyModules modules source pulse names (newNewModules, newLow, newHigh) = applySteps newModules (t ++ result) in (newNewModules, low + newLow, high + newHigh) pressButton :: Modules -> (Modules, Int, Int) pressButton modules = let (newModules, low, high) = applySteps modules [("button", ["broadcaster"], False)] in (newModules, low + 1, high) pressButtonNTimes' :: Modules -> Int -> Int -> Int -> Int -> (Int, Int) pressButtonNTimes' modules low high i n | i == n = (low, high) | otherwise = let (newModules, newLow, newHigh) = pressButton modules in pressButtonNTimes' newModules (low + newLow) (high + newHigh) (i + 1) n pressButtonNTimes :: Modules -> Int -> (Int, Int) pressButtonNTimes modules = pressButtonNTimes' modules 0 0 0