never executed always true always false
    1 {-|
    2 Module:      Y2015.D19
    3 Description: Advent of Code Day 19 Solutions.
    4 License:     MIT
    5 Maintainer:  @tylerjl
    6 
    7 Solutions to the day 19 set of problems for <adventofcode.com>.
    8 -}
    9 
   10 module Y2015.D19 (distinctMols, molSteps) where
   11 
   12 import Data.Char (isLower, isUpper)
   13 import Data.List (foldl', inits, tails)
   14 import Data.Map.Strict (Map)
   15 import qualified Data.Map.Strict as M
   16 import Data.Set  (Set)
   17 import qualified Data.Set as S
   18 
   19 type Mol   = [String]
   20 type Repls = Map String (Set String)
   21 
   22 -- |Returns the number of steps required to form a specified molecule
   23 molSteps :: String -- ^ Target molecule composition as a raw string
   24          -> Int    -- ^ Number of steps required to create indicated molecule
   25 molSteps = (+) (-1) . sum . map replCount . toMol . last . lines
   26   where replCount "Rn" =  0
   27         replCount "Ar" =  0
   28         replCount "Y"  = -1
   29         replCount _    =  1
   30 
   31 -- |Finds the number of possible distinct molecules
   32 distinctMols :: String -- ^ List of starting molecules as a raw string
   33              -> Int    -- ^ Number of distinct modules that can be formed
   34 distinctMols s = S.size $ compounds mols repls
   35   where input = lines s
   36         mols  = toMol $ last input
   37         repls = toRepls $ init input
   38 
   39 compounds :: Mol -> Repls -> Set String
   40 compounds m r = foldl' S.union S.empty $ map combine molTrips
   41   where molTrips = zip3 (inits m) m (tail $ tails m)
   42         combine t@(_,m',_) = subRepl t $ M.findWithDefault S.empty m' r
   43 
   44 subRepl :: (Mol, String, Mol) -> Set String -> Set String
   45 subRepl (pre,_,post) = foldl' (flip S.insert) S.empty
   46                        . map (concat . construct) . S.toList
   47   where construct repl = pre ++ [repl] ++ post
   48 
   49 toRepls :: [String] -> Repls
   50 toRepls = M.fromListWith S.union . map (molPair S.singleton . words)
   51 
   52 molPair :: (a -> b) -> [a] -> (a, b)
   53 molPair f [from,_,to] = (from, f to)
   54 molPair f xs = (head xs, f $ last xs)
   55 
   56 toMol :: String -> Mol
   57 toMol []                                = []
   58 toMol (x:y:ys) | isUpper x && isLower y = (x:[y]) : toMol ys
   59 toMol (x:xs)   | isUpper x || x == 'e'  = [x]     : toMol xs
   60                | otherwise              = toMol xs