Advent of Code 2025
1module Day4 where
2
3import qualified Data.Map as Map
4import Data.Map (Map)
5
6type Grid = Map (Int,Int) Char
7
8enumerate :: [a] -> [(Int,a)]
9enumerate l = zip [0..] l
10
11addRow :: Int -> String -> Grid -> Grid
12addRow y row grid =
13 foldl
14 (\g (x,c) -> Map.insert (x,y) c g)
15 grid
16 (enumerate row)
17
18parse :: String -> Grid
19parse s =
20 foldl
21 (\g (x,row) -> addRow x row g)
22 Map.empty
23 (enumerate $ lines s)
24
25neighbors :: (Int,Int) -> [(Int,Int)]
26neighbors (x,y) =
27 [(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)]
28
29isOccupied :: Grid -> (Int,Int) -> Bool
30isOccupied grid p = Map.lookup p grid == Just '@'
31
32isAccessible :: Grid -> (Int,Int) -> Char -> Bool
33isAccessible grid p '@' =
34 length (filter (isOccupied grid) (neighbors p)) < 4
35isAccessible _ _ _ = False
36
37part1 :: String -> String
38part1 input =
39 let grid = parse input
40 in show $
41 length $
42 Map.filterWithKey (isAccessible grid) grid
43
44removeAccessible :: Grid -> Grid
45removeAccessible grid =
46 let accessible = Map.filterWithKey (isAccessible grid) grid
47 in Map.difference grid accessible
48
49removeAll :: Grid -> Grid
50removeAll grid =
51 let grids = iterate removeAccessible grid
52 stabilized (x : y : gs) =
53 if Map.size x == Map.size y then
54 x
55 else
56 stabilized (y : gs)
57 in stabilized grids
58
59part2 :: String -> String
60part2 input =
61 let grid = parse input
62 in show $ Map.size $ Map.difference grid (removeAll grid)