aboutsummaryrefslogtreecommitdiffstats
path: root/day11/main.hs
diff options
context:
space:
mode:
Diffstat (limited to 'day11/main.hs')
-rw-r--r--day11/main.hs110
1 files changed, 110 insertions, 0 deletions
diff --git a/day11/main.hs b/day11/main.hs
new file mode 100644
index 0000000..a3ec51e
--- /dev/null
+++ b/day11/main.hs
@@ -0,0 +1,110 @@
+module Main where
+
+import Control.Monad (foldM)
+import Data.Char (digitToInt)
+import Data.Either (fromLeft)
+import Data.List (foldl', intercalate)
+import Data.Map (Map, (!))
+import qualified Data.Map as Map
+import Debug.Trace (trace, traceShow)
+import Utils
+
+type Dim = (Int, Int)
+
+type Point = (Int, Int)
+
+type State = Map Point Int
+
+printState :: Dim -> State -> IO ()
+printState dim@(xsize, ysize) state =
+ let coords = [(x, y) | y <- [0 .. ysize - 1], x <- [0 .. xsize -1]]
+ elems = coords $> map (state !)
+ in splitEvery xsize (elems $> map show .> intercalate "")
+ $> map putStrLn
+ .> sequence_
+
+pointSum :: Point -> Point -> Point
+pointSum (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)
+
+incAllBy1 :: State -> State
+incAllBy1 = Map.map (+ 1)
+
+flash :: State -> Dim -> Point -> State
+flash state dim@(xsize, ysize) p =
+ let flashed = neighbors state dim p
+ in Map.mapWithKey (\p' v -> if p' `elem` flashed then v + 1 else v) state
+
+findOverNine :: State -> [Point] -> Maybe Point
+findOverNine state alreadyFlashed =
+ let ps = Map.filterWithKey (\k v -> v > 9 && k `notElem` alreadyFlashed) state $> Map.keys
+ in if not (null ps)
+ then Just (head ps)
+ else Nothing
+
+resetFlashed :: State -> State
+resetFlashed = Map.map (\v -> if v > 9 then 0 else v)
+
+neighbors :: State -> Dim -> Point -> [Point]
+neighbors state (xsize, ysize) p@(x, y) =
+ let diffs = [(dx, dy) | dx <- [-1, 0, 1], dy <- [-1, 0, 1]]
+ ps = diffs $> map (pointSum p)
+ in filter (`Map.member` state) ps
+
+flashIfNotYetFlashed :: State -> Dim -> [Point] -> Point -> ([Point], State)
+flashIfNotYetFlashed state dim alreadyFlashed p
+ | p `elem` alreadyFlashed = (alreadyFlashed, state)
+ | otherwise =
+ let state' = flash state dim p
+ in (p : alreadyFlashed, state')
+
+iterateFlashes state dim alreadyFlashed =
+ let unstableM = findOverNine state alreadyFlashed
+ in case unstableM of
+ Nothing -> (length alreadyFlashed, state)
+ Just p ->
+ let (alreadyFlashed', state') = flashIfNotYetFlashed state dim alreadyFlashed p
+ (n, res) = iterateFlashes state' dim alreadyFlashed'
+ in if length alreadyFlashed' == length alreadyFlashed
+ then (length alreadyFlashed, state')
+ else (n, res)
+
+step state dim =
+ let state' = incAllBy1 state
+ (flashesN, state'') = iterateFlashes state' dim []
+ in (flashesN, resetFlashed state'')
+
+e1 :: State -> Dim -> (Int, State)
+e1 hmap dim =
+ foldl'
+ ( \(n, state) _ ->
+ let (n', state') = step state dim
+ in (n + n', state')
+ )
+ (0, hmap)
+ [1 .. 100]
+
+e2 :: State -> Dim -> Int
+e2 hmap dim@(xsize, ysize) =
+ foldM
+ ( \state s ->
+ let (n', state') = step state dim
+ in if n' == xsize * ysize
+ then Left s
+ else Right state'
+ )
+ hmap
+ [1 ..]
+ $> (\(Left s) -> s)
+
+main :: IO ()
+main =
+ do
+ contents <- getContents
+
+ let input = contents $> lines .> map (map digitToInt)
+ let dim@(ysize, xsize) = (length input, length (head input))
+ let coords = [(x, y) | y <- [0 .. ysize - 1], x <- [0 .. xsize -1]]
+ let hmap = Map.fromList $ zip coords (concat input)
+
+ e1 hmap dim $> fst .> print
+ e2 hmap dim $> print