|
| 1 | +module Day4 |
| 2 | + |
| 3 | +import Prelude |
| 4 | +import Node |
| 5 | +import Aoc |
| 6 | +import Data.SortedMap |
| 7 | + |
| 8 | +gridPoints : String → List (Char × Int × Int) |
| 9 | +gridPoints text = go 0 0 (unpack text) Nil |
| 10 | + where |
| 11 | + go : Int → Int → List Char → List (Char × Int × Int) → List (Char × Int × Int) |
| 12 | + go row col Nil points = points |
| 13 | + go row col ('\n' :: cs) points = go (row + 1) 0 cs points |
| 14 | + go row col (c :: cs) points = go row (col + 1) cs ((c,row,col) :: points) |
| 15 | + |
| 16 | +Grid : U |
| 17 | +Grid = SortedMap Point Int |
| 18 | + |
| 19 | +getGrid : String → Grid |
| 20 | +getGrid text = foldl update (EmptyMap compare) $ gridPoints text |
| 21 | + where |
| 22 | + update : Grid → Char × Point → Grid |
| 23 | + update grid (c,pt) = updateMap pt (ord c) grid |
| 24 | + |
| 25 | +neighbors : Point → List Point |
| 26 | +neighbors pt = map (_+_ pt) ( |
| 27 | + (0 - 1, 0 - 1) :: (0 - 1, 0) :: (0 - 1, 1) :: |
| 28 | + (0, 0 - 1) :: (0, 1) :: |
| 29 | + (1, 0 - 1) :: (1, 0) :: (1, 1) :: Nil) |
| 30 | + |
| 31 | +part1 : Grid → Int |
| 32 | +part1 grid = go 0 $ toList grid |
| 33 | + where |
| 34 | + full : Maybe Int → Bool |
| 35 | + full (Just 64) = True |
| 36 | + full _ = False |
| 37 | + |
| 38 | + go : Int → List (Point × Int) → Int |
| 39 | + go acc Nil = acc |
| 40 | + go acc ((pt,64) :: rest) = |
| 41 | + let count = length' $ filter full $ map (flip lookupMap' grid) $ neighbors pt |
| 42 | + in if count < 4 then go (acc + 1) rest else go acc rest |
| 43 | + go acc (_ :: rest) = go acc rest |
| 44 | + |
| 45 | +part2 : Grid → Int |
| 46 | +part2 grid = |
| 47 | + let todo = filter (\ x => snd x == 64) $ toList grid |
| 48 | + in go todo emptyMap grid |
| 49 | + where |
| 50 | + full : (Point × Int) → Bool |
| 51 | + full (_, 64) = True |
| 52 | + full _ = False |
| 53 | + |
| 54 | + helper : Grid → (Point × Int) → Grid |
| 55 | + helper todo (k, v) = updateMap k v todo |
| 56 | + |
| 57 | + go : List (Point × Int) → Grid → Grid → Int |
| 58 | + go Nil todo grid = do |
| 59 | + case toList todo of |
| 60 | + Nil => length' $ filter (\ x => snd x == 0) $ toList {Point} {Int} grid |
| 61 | + todo => go todo emptyMap grid |
| 62 | + go ((pt, _) :: xs) todo grid = do |
| 63 | + let pts = filter full $ mapMaybe (flip lookupMap grid) $ neighbors pt |
| 64 | + if length' pts < 4 |
| 65 | + then go xs (foldl helper todo pts) (updateMap pt 0 grid) |
| 66 | + else go xs todo grid |
| 67 | + |
| 68 | +run : String -> IO Unit |
| 69 | +run fn = do |
| 70 | + putStrLn fn |
| 71 | + text <- readFile fn |
| 72 | + let grid = getGrid text |
| 73 | + putStrLn $ "part1 " ++ show (part1 grid) |
| 74 | + putStrLn $ "part2 " ++ show (part2 grid) |
| 75 | + |
| 76 | +main : IO Unit |
| 77 | +main = do |
| 78 | + run "aoc2025/day4/eg.txt" |
| 79 | + run "aoc2025/day4/input.txt" |
0 commit comments