Advent of Code 2025

Day 4

Changed files
+57 -2
src
+57 -2
src/Day4.hs
···
module Day4 where
part1 :: String -> String
-
part1 _ = "Day 4 part 1"
part2 :: String -> String
-
part2 _ = "Day 4 part 2"
···
module Day4 where
+
import qualified Data.Map as Map
+
import Data.Map (Map)
+
+
type Grid = Map (Int,Int) Char
+
+
enumerate :: [a] -> [(Int,a)]
+
enumerate l = zip [0..] l
+
+
addRow :: Int -> String -> Grid -> Grid
+
addRow y row grid =
+
foldl
+
(\g (x,c) -> Map.insert (x,y) c g)
+
grid
+
(enumerate row)
+
+
parse :: String -> Grid
+
parse s =
+
foldl
+
(\g (x,row) -> addRow x row g)
+
Map.empty
+
(enumerate $ lines s)
+
+
neighbors :: (Int,Int) -> [(Int,Int)]
+
neighbors (x,y) =
+
[(x-1,y-1),(x,y-1),(x+1,y-1),(x-1,y),(x+1,y),(x-1,y+1),(x,y+1),(x+1,y+1)]
+
+
isOccupied :: Grid -> (Int,Int) -> Bool
+
isOccupied grid p = Map.lookup p grid == Just '@'
+
+
isAccessible :: Grid -> (Int,Int) -> Char -> Bool
+
isAccessible grid p '@' =
+
length (filter (isOccupied grid) (neighbors p)) < 4
+
isAccessible _ _ _ = False
+
part1 :: String -> String
+
part1 input =
+
let grid = parse input
+
in show $
+
length $
+
Map.filterWithKey (isAccessible grid) grid
+
+
removeAccessible :: Grid -> Grid
+
removeAccessible grid =
+
let accessible = Map.filterWithKey (isAccessible grid) grid
+
in Map.difference grid accessible
+
+
removeAll :: Grid -> Grid
+
removeAll grid =
+
let grids = iterate removeAccessible grid
+
stabilized (x : y : gs) =
+
if Map.size x == Map.size y then
+
x
+
else
+
stabilized (y : gs)
+
in stabilized grids
part2 :: String -> String
+
part2 input =
+
let grid = parse input
+
in show $ Map.size $ Map.difference grid (removeAll grid)