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