1 -- Writeup at https://work.njae.me.uk/2021/12/18/advent-of-code-2021-day-16/
4 import Control.Monad.State.Strict
5 import Control.Monad.Reader
6 -- import Control.Monad.Writer
7 import Control.Monad.RWS.Strict
12 import qualified Data.Set as S
13 import Linear (V2(..), (^+^))
15 type Pixel = V2 Int -- row, column
19 , distantPixel :: Bool
20 , explicitRegion :: (Pixel, Pixel)
23 type Enhancement = [Bool]
25 type ImageEnhancer = RWS Enhancement [Int] Image
29 do text <- readFile "data/advent20.txt"
30 let (enhancement, image) = parse text
31 print $ part1 enhancement image
32 print $ part2 enhancement image
34 -- part1 enhancement image = s
35 -- where (s, image', _) = runRWS (enhanceImage 2) enhancement image
37 part1 enhancement image = fst $ evalRWS (enhanceImage 2) enhancement image
39 part2 enhancement image = fst $ evalRWS (enhanceImage 50) enhancement image
41 enhanceImage :: Int -> ImageEnhancer Int
42 enhanceImage 0 = do image <- get
43 return $ S.size $ grid image
44 enhanceImage n = do newImage
47 newImage :: ImageEnhancer ()
50 let region = explicitRegion image
51 let region' = expandRegion region
52 let heres = range region'
53 let distant = distantPixel image
54 newPixelStates <- mapM newPixel heres
55 let grid' = S.fromList $ catMaybes newPixelStates
57 let distant' = if distant then (last enhancement) else (head enhancement)
58 put $ Image {grid = grid', distantPixel = distant', explicitRegion = region'}
61 showImage :: Image -> String
63 unlines $ [ [showPixel (V2 r c) | c <- [minC..maxC] ] | r <- [minR..maxR]]
64 where (V2 minR minC, V2 maxR maxC) = explicitRegion image
66 showPixel here = if here `S.member` g then '█' else ' '
68 newPixel :: Pixel -> ImageEnhancer (Maybe Pixel)
70 do stencil <- findStencil here
71 let i = intify stencil
73 return $ if enh!!i then Just here else Nothing
75 findStencil :: Pixel -> ImageEnhancer [Bool]
77 do let nbrs = map (here ^+^) neighbours
79 d <- gets distantPixel
80 r <- gets explicitRegion
81 return $ map (findContents g d r) nbrs
83 findContents :: S.Set Pixel -> Bool -> (Pixel, Pixel) -> Pixel -> Bool
84 findContents grid distant region here
85 | inRange region here = here `S.member` grid
90 neighbours = [V2 r c | r <- [-1, 0, 1], c <- [-1, 0, 1]]
92 expandRegion :: (Pixel, Pixel) -> (Pixel, Pixel)
93 expandRegion ((V2 r0 c0), (V2 r1 c1)) = (V2 (r0 - 1) (c0 - 1), V2 (r1 + 1) (c1 + 1))
95 parse text = (enhancement, image)
97 enhancement = [ c == '#' | c <- head ls]
98 image = mkImage $ drop 2 ls
101 mkImage :: [String] -> Image
102 mkImage rows = Image { grid = grid, distantPixel = False
103 , explicitRegion = ((V2 0 0), (V2 maxRow maxCol))
105 where maxRow = length rows - 1
106 maxCol = (length $ head rows) - 1
107 grid = S.fromList [V2 r c | r <- [0..maxRow], c <- [0..maxCol], (rows!!r)!!c == '#']
110 intify pixels = foldl' addBit 0 pixels
111 where addBit w b = (w * 2) + (if b then 1 else 0)
113 -- wordify :: BS.BitString -> Integer
114 -- wordify bs = foldl' addBit 0 $ BS.to01List bs
115 -- where addBit w b = (w * 2) + (fromIntegral b)