never executed always true always false
1 {-# LANGUAGE FlexibleContexts #-}
2 {-|
3 Module: Y2021.D06
4 Description: Advent of Code 2021 Day 06 Solutions.
5 License: MIT
6 Maintainer: @tylerjl
7
8 Solutions to the 2021 day 06 set of problems for <adventofcode.com>.
9 -}
10 module Y2021.D06 where
11
12 import Data.Either.Utils (fromRight)
13 import Data.Text (Text)
14 import qualified Data.Text as T
15 import Text.Parsec hiding (Empty)
16 import Y2015.Util (regularParse', intParser')
17
18 import qualified Data.IntMap.Strict as M
19 import qualified Data.Vector.Unboxed.Mutable as V
20 import Control.Monad (forM_, replicateM_)
21 import Control.Monad.ST (runST)
22 import qualified Data.Sequence as Seq
23 import Data.Sequence (Seq(..))
24 import Data.List (elemIndices)
25 import Witch
26 import qualified Data.Attoparsec.Text as AP
27
28 -- |Solve part A
29 part6A :: Text -> Int
30 part6A = solve6 80 . parseFish
31
32 -- |Solve part A, with unboxed mutable vectors
33 part6AMV :: Text -> Int
34 part6AMV = solve6MV 80 . parseFish
35
36 -- |Solve part A, with sequences
37 part6ASeq :: Text -> Int
38 part6ASeq = solve6Seq 80 . Seq.fromFunction 9 . build . parseFish
39 where build fish n = length $ elemIndices n fish
40
41 -- |Solve part B
42 part6B :: Text -> Int
43 part6B = solve6 256 . parseFish
44
45 -- |Solve part B, with unboxed mutable vectors
46 part6BMV :: Text -> Int
47 part6BMV = solve6MV 256 . parseFish
48
49 -- |Solve part B, with sequences
50 part6BSeq :: Text -> Int
51 part6BSeq = solve6Seq 256 . Seq.fromFunction 9 . build . parseFish
52 where build fish n = length $ elemIndices n fish
53
54 solve6Seq :: Int -> Seq Int -> Int
55 solve6Seq n fish = Seq.foldlWithIndex sum' 0 $ iterate solve6Seq' fish !! n
56 where sum' acc _ el = acc + el
57
58 solve6Seq' :: Seq Int -> Seq Int
59 solve6Seq' (a:<|b:<|c:<|d:<|e:<|f:<|g:<|h:<|i:<|Empty)=
60 b:<|c:<|d:<|e:<|f:<|g:<|h+a:<|i:<|a:<|Empty
61 solve6Seq' _ = error "unexpected fish sequence size"
62
63 -- |Solution algorithm using super aggressive mutable unboxed vectors.
64 solve6MV :: Int -> [Int] -> Int
65 solve6MV days fish = runST $ do
66 vec <- V.replicate 9 0
67 forM_ fish $ \fish' -> do
68 V.modify vec (+ 1) fish'
69 replicateM_ days $ do
70 newFish <- V.read vec 0
71 V.move (V.slice 0 8 vec) (V.slice 1 8 vec)
72 V.write vec 8 newFish
73 V.modify vec (+ newFish) 6
74 V.foldl' (+) 0 vec
75
76 -- |Iterate for a given number of days given a starting value and return the
77 -- total.
78 solve6 :: Int -> [Int] -> Int
79 solve6 n
80 = M.foldl' (+) 0
81 . flip (!!) n
82 . iterate breed
83 . M.fromListWith (+)
84 . flip zip (repeat 1)
85
86 -- |Simulate one day passing for the collection of fish.
87 breed :: Num a => M.IntMap a -> M.IntMap a
88 breed fish =
89 M.insert 8 newFish $
90 M.mapKeysWith (+) step fish
91 where
92 step (pred -> age) | age < 0 = 6
93 | otherwise = age
94 newFish = M.findWithDefault 0 0 fish
95
96 -- |Parse puzzle input into a list of `Int`s.
97 parseFish :: Text -> [Int]
98 parseFish = fromRight . regularParse' fishParser
99 where fishParser = intParser' `sepBy1` char ',' <* newline <* eof
100
101 -- |Parse puzzle input into a list of `Int`s but do so with a dumb parser.
102 parseFish' :: Text -> [Int]
103 parseFish' = map (read . into @String) . T.splitOn ","
104
105 -- |Parse puzzle input into a list of `Int`s but do so with a dumb parser.
106 parseFish'' :: Text -> [Int]
107 parseFish'' = fromRight . AP.parseOnly parser
108 where parser = AP.decimal `AP.sepBy` AP.char ',' <* AP.endOfLine