-
-manyButtonPress :: Int -> (Int, Int) -> Network -> NetworkState -> (Int, Int)
-manyButtonPress 0 (highs, lows) _ _ = (highs, lows)
-manyButtonPress n (highs, lows) network state =
- manyButtonPress (n - 1) (highs + length hs, lows + length ls) network state'
- where (state', pulses) = buttonPress network state
- (hs, ls) = partition ((== High) . _level) pulses
+part2 network modules = foldl' lcm 1 cycleLengths
+ where (_, lxPulses) =
+ (!! 10000) $ iterate (pressAndEvaluate network part2Extractor) (state0, [(0, [])])
+ state0 = NetworkState modules Q.empty
+ lxHighs = filter (not . null . snd) lxPulses
+ cycleLengths = fmap ((fst . head) . sort) $
+ groupBy ((==) `on` (_source . snd)) $
+ sortBy (compare `on` (\(_, p) -> p ^. source)) $
+ fmap (\(n, ps) -> (n, head ps)) lxHighs
+
+pressAndEvaluate :: Network -> (a -> [Pulse] -> a) -> (NetworkState, a) -> (NetworkState, a)
+pressAndEvaluate network resultExtractor (state0, result0) = (state1, result1)
+ where (state1, pulses) = buttonPress network state0
+ result1 = resultExtractor result0 pulses
+
+part1Extractor :: (Int, Int) -> [Pulse] -> (Int, Int)
+part1Extractor (highs, lows) pulses = (highs + length hs, lows + length ls)
+ where (hs, ls) = partition ((== High) . _level) pulses
+
+part2Extractor :: [(Int, [Pulse])] -> [Pulse] -> [(Int, [Pulse])]
+part2Extractor allRs@((i, _):rs) pulses = (i + 1, lxPulses) : allRs
+ where lxPulses = filter catchLx pulses
+ catchLx (Pulse _ High "lx") = True
+ catchLx _ = False