adventofcode-2021/11/octoflash.hs

94 lines
2.7 KiB
Haskell
Raw Normal View History

2021-12-14 00:40:52 +00:00
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