never executed always true always false
    1 {-|
    2 Module:      Y2015.D15
    3 Description: Advent of Code Day 15 Solutions.
    4 License:     MIT
    5 Maintainer:  @tylerjl
    6 
    7 Solutions to the day 15 set of problems for <adventofcode.com>.
    8 -}
    9 
   10 module Y2015.D15 (calorieScore, cookieScore) where
   11 
   12 import Data.List (foldl')
   13 
   14 data Ingredient = Ingredient { capacity   :: Int
   15                              , durability :: Int
   16                              , flavor     :: Int
   17                              , texture    :: Int
   18                              , calories   :: Int
   19                              } deriving (Show, Eq)
   20 
   21 -- |Finds a calorie score for a cookie recipe
   22 calorieScore :: String -- ^ Raw string of recipe
   23              -> Int    -- ^ Calorie score
   24 calorieScore = recipeCombos ((==) 500 . last)
   25 
   26 -- |Calculates a cookie score
   27 cookieScore :: String -- ^ Cookie recipe input
   28             -> Int    -- ^ Calculated cookie score
   29 cookieScore = recipeCombos (const True)
   30 
   31 recipeCombos :: ([Int] -> Bool) -> String -> Int
   32 recipeCombos f s = maximum $ map (product . init) $ filter f mixtures
   33     where ingredients  = toIngredients s
   34           measurements = length ingredients `partsOf` 100
   35           mixtures     = [ingredients `recipeSum` x | x <- measurements]
   36 
   37 recipeSum :: [Ingredient] -> [Int] -> [Int]
   38 recipeSum i p = map (max 0) $ foldl' (zipWith (+)) [0,0,0,0,0] portions
   39     where portions = zipWith toScores i p
   40 
   41 toScores :: Ingredient -> Int -> [Int]
   42 toScores Ingredient { capacity = c, durability = d, flavor = f, texture = t, calories = ca } =
   43         flip map [c,d,f,t,ca] . (*)
   44 
   45 partsOf :: Int -> Int -> [[Int]]
   46 partsOf n total | n > 1     = [x : y | x <- [1..(total-1)], y <- (n-1) `partsOf` (total-x)]
   47                 | otherwise = [[total]]
   48 
   49 toIngredients :: String -> [Ingredient]
   50 toIngredients = map (toIngredient . words) . lines . filter (/= ',')
   51 
   52 toIngredient :: [String] -> Ingredient
   53 toIngredient [_,_,c,_,d,_,f,_,t,_,ca] =
   54     Ingredient { capacity   = read c
   55                , durability = read d
   56                , flavor     = read f
   57                , texture    = read t
   58                , calories   = read ca
   59                }
   60 toIngredient _ =
   61     Ingredient { capacity   = 0
   62                , durability = 0
   63                , flavor     = 0
   64                , texture    = 0
   65                , calories   = 0
   66                }