import Data.Char (digitToInt) main :: IO () main = do input <- getContents let octopodes = (map (map digitToInt) . lines) input (putStrLn . show . solution1) octopodes (putStrLn . show . solution2) octopodes solution1 :: [[Int]] -> Int solution1 m = snd (iterate flashSimulate (m, 0) !! 100) solution2 :: [[Int]] -> Int solution2 m = countUntil (all (all (==0)) . fst) flashSimulate (m, 0) flashSimulate :: ([[Int]], Int) -> ([[Int]], Int) flashSimulate (octopodes, flashes) = (refreshOctopodes exhaustedOctopodes, flashes + countExhaustedOctopodes exhaustedOctopodes) where exhaustedOctopodes = flashStep octopodes countExhaustedOctopodes = foldr (\l a -> length l + a) 0 . map (filter (> 9)) refreshOctopodes = map (map (\o -> if o > 9 then 0 else o)) flashStep :: [[Int]] -> [[Int]] flashStep = propagateFlashes . map (map (+1)) where propagateFlashes :: [[Int]] -> [[Int]] propagateFlashes = until allExhausted flashOctopi where allExhausted :: [[Int]] -> Bool allExhausted = all (all (/= 10)) flashOctopi :: [[Int]] -> [[Int]] flashOctopi m = map (map (incrementFlashing m)) [[(x, y) | y <- [0..length (m !! x) - 1]] | x <- [0..length m - 1]] where incrementFlashing ::[[Int]] -> (Int, Int) -> Int incrementFlashing m' o | charge < 10 && newCharge > 10 = 10 -- Ensure we don't miss an increment | otherwise = charge + numFlashingNeighbors o where newCharge = charge + numFlashingNeighbors o charge = m' !!! o numFlashingNeighbors :: (Int, Int) -> Int numFlashingNeighbors = length . filter (\o -> (m !!! o) == 10) . (flip adjacent m) (!!!) :: [[Int]] -> (Int, Int) -> Int (!!!) m index = m !! (fst index) !! (snd index) countUntil :: (a -> Bool) -> (a -> a) -> a -> Int countUntil p f = call where call x | p x = 0 | otherwise = call (f x) + 1 adjacent :: (Int, Int) -> [[Int]] -> [(Int, Int)] adjacent (x, y) m = [(x+i, y+j) | i <- [-1..1], j <- [-1..1], -- (i, j) /= (0, 0), x+i >= 0, y+j >= 0, x+i < length m, y+j < length (m !! 0)] -- Tests testInput1 = [ "5483143223", "2745854711", "5264556173", "6141336146", "6357385478", "4167524645", "2176841721", "6882881134", "4846848554", "5283751526" ] parsedTestInput1 = map (map digitToInt) testInput1 testInput2 = [ "11111", "19991", "19191", "19991", "11111" ] parsedTestInput2 = map (map digitToInt) testInput2 test1 = solution1 parsedTestInput1 test2 = solution2 parsedTestInput1