Advertisement
bss03

Advent of Code 2020 Day 11

Dec 11th, 2020
1,432
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. {-# language DeriveFunctor #-}
  2. {-# language DeriveTraversable #-}
  3. {-# language RecordWildCards #-}
  4.  
  5. import Control.Applicative (ZipList(ZipList), getZipList)
  6. import Control.Monad ((>=>), (<=<))
  7. import Data.List (tails, unfoldr)
  8. import Data.List.NonEmpty (NonEmpty((:|)), nonEmpty)
  9. import Data.Maybe (mapMaybe)
  10.  
  11. change1 :: Char -> Int -> Char
  12. change1 'L' 0 = '#'
  13. change1 '#' n | 4 <= n = 'L'
  14. change1 c _ = c
  15.  
  16. update1 :: [String] -> Maybe Char
  17. update1 ((ul:u:ur:_):(l:c:r:_):(bl:b:br:_):_) = pure . change1 c . length $ filter ('#' ==) [ul,u,ur,l,r,bl,b,br]
  18. update1 ([ul,u]:[l,c]:[bl,b]:_) = pure . change1 c . length $ filter ('#' ==) [ul,u,l,bl,b]
  19. update1 [(ul:u:ur:_),(l:c:r:_)] = pure . change1 c . length $ filter ('#' ==) [ul,u,ur,l,r]
  20. update1 [[ul,u],[l,c]] = pure . change1 c . length $ filter ('#' ==) [ul,u,l]
  21. update1 _ = Nothing
  22.  
  23. update1All :: [String] -> [String]
  24. update1All = filter (not . null) . map (mapMaybe update1 . horiz) . vert
  25.  
  26. vert :: [String] -> [[String]]
  27. vert [] = []
  28. vert l@(h:_) = tails $ ('L' <$ h) : l
  29.  
  30. horiz :: [String] -> [[String]]
  31. horiz [] = []
  32. horiz l = getZipList $ traverse (ZipList . tails . ('L':)) l
  33.  
  34. fixUpdate1 :: [String] -> [String]
  35. fixUpdate1 l = if u == l then u else fixUpdate1 u
  36.    where u = update1All l
  37.  
  38. data Zip a
  39.   = MkZip
  40.   { revBefore :: [a]
  41.   , current :: a
  42.   , future :: [a]
  43.   } deriving (Eq, Show, Functor, Foldable, Traversable)
  44.  
  45. instance Applicative Zip where
  46.   pure x = MkZip { revBefore = repeat x, current = x, future = repeat x }
  47.   f <*> x =
  48.     MkZip
  49.     { revBefore = zipWith ($) (revBefore f) (revBefore x)
  50.     , current = current f (current x)
  51.     , future = zipWith ($) (future f) (future x)
  52.     }
  53.  
  54. toZip :: NonEmpty a -> Zip a
  55. toZip (x:|xs) = MkZip { revBefore = [], current = x, future = xs }
  56.  
  57. reverseOnto :: [a] -> [a] -> [a]
  58. reverseOnto [] l = l
  59. reverseOnto (h:t) l = reverseOnto t (h : l)
  60.  
  61. toList :: Zip a -> [a]
  62. toList MkZip{..} = reverseOnto revBefore (current : future)
  63.  
  64. moveNext :: Zip a -> Maybe (Zip a)
  65. moveNext MkZip{..} = fmap mn $ nonEmpty future
  66.  where
  67.   mn (x:|xs) =
  68.     MkZip
  69.     { revBefore = current : revBefore
  70.     , current = x
  71.     , future = xs
  72.     }
  73.  
  74. movePrev :: Zip a -> Maybe (Zip a)
  75. movePrev MkZip{..} = fmap mp $ nonEmpty revBefore
  76.  where
  77.   mp (x:|xs) =
  78.     MkZip
  79.     { revBefore = xs
  80.     , current = x
  81.     , future = current : future
  82.     }
  83.  
  84. moveD :: Zip (Zip a) -> Maybe (Zip (Zip a))
  85. moveD = moveNext
  86.  
  87. moveU :: Zip (Zip a) -> Maybe (Zip (Zip a))
  88. moveU = movePrev
  89.  
  90. moveR :: Zip (Zip a) -> Maybe (Zip (Zip a))
  91. moveR = traverse moveNext
  92.  
  93. moveL :: Zip (Zip a) -> Maybe (Zip (Zip a))
  94. moveL = traverse movePrev
  95.  
  96. search :: (Zip (Zip Char) -> Maybe (Zip (Zip Char))) -> Zip (Zip Char) -> Bool
  97. search step = search'
  98. where
  99.  search' area = case step area of
  100.    Nothing -> False
  101.    Just next -> case current $ current next of
  102.      '#' -> True
  103.      'L' -> False
  104.      _ -> search' next
  105.  
  106. change2 :: Char -> Int -> Char
  107. change2 'L' 0 = '#'
  108. change2 '#' n | 5 <= n = 'L'
  109. change2 c _ = c
  110.  
  111. update2 :: Zip (Zip Char) -> Char
  112. update2 target = change2 (current $ current target) . length $ filter (flip search target) dirs
  113. where
  114.  dirs =
  115.    [ moveU >=> moveL, moveU, moveU >=> moveR
  116.    , moveL, moveR
  117.    , moveD >=> moveL, moveD, moveD >=> moveR
  118.    ]
  119.  
  120. update2All :: Zip (Zip Char) -> Zip (Zip Char)
  121. update2All = fmap (fmap update2 . traverse dupZ) . dupZ
  122.  
  123. dupZ :: Zip a -> Zip (Zip a)
  124. dupZ z =
  125.  MkZip
  126.  { revBefore = unfoldr mp z
  127.  , current = z
  128.  , future = unfoldr mn z
  129.  }
  130. where
  131.  mp = fmap (\x -> (x,x)) . movePrev
  132.  mn = fmap (\x -> (x,x)) . moveNext
  133.  
  134. fixUpdate2 :: Zip (Zip Char) -> Zip (Zip Char)
  135. fixUpdate2 z = if z == u then z else fixUpdate2 u
  136. where u = update2All z
  137.  
  138. interactive :: Show a => (String -> a) -> IO ()
  139. interactive f = print . f =<< getContents
  140.  
  141. part1 :: IO ()
  142. part1 = interactive (sum . map (length . filter ('#' ==)) . fixUpdate1 . lines)
  143.  
  144. main :: IO ()
  145. main = interactive (fmap (sum . map (length . filter ('#' ==)) . toList . fmap toList . fixUpdate2 . toZip . fmap toZip) . (traverse nonEmpty <=< nonEmpty) . lines)
  146.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement