never executed always true always false
    1 {-# LANGUAGE TupleSections #-}
    2 {-|
    3 Module:      Y2021.D05
    4 Description: Advent of Code 2021 Day 05 Solutions.
    5 License:     MIT
    6 Maintainer:  @tylerjl
    7 
    8 Solutions to the 2021 day 05 set of problems for <adventofcode.com>.
    9 -}
   10 module Y2021.D05 where
   11 
   12 import AoC.Utils
   13 import Data.Attoparsec.Text
   14 import Data.Either.Utils   (fromRight)
   15 import Data.HashMap.Strict (HashMap)
   16 import Data.Monoid
   17 import Data.Text           (Text)
   18 
   19 import qualified Data.HashMap.Strict as M
   20 
   21 -- |Makes some signatures easier to read
   22 type Point = (Int, Int)
   23 -- |Makes some signatures easier to read
   24 type Line = (Point, Point)
   25 -- |Makes some signatures easier to read
   26 type Points = HashMap Point (Sum Int)
   27 
   28 -- |Solve part A
   29 part5A :: Text -> Int
   30 part5A = solve5 (filter part5APredicate)
   31 
   32 part5APredicate :: Line -> Bool
   33 part5APredicate ((x1, y1), (x2, y2))
   34   = x1 == x2 || y1 == y2
   35 
   36 -- |Solve part B
   37 part5B :: Text -> Int
   38 part5B = solve5 id
   39 
   40 -- |Higher-order function solution to share parts A and B.
   41 solve5 :: ([Line] -> [Line]) -> Text -> Int
   42 solve5 f =
   43   M.size .
   44   M.filter (> 1) . M.fromListWith mappend . concatMap lineTo . f . parseVents
   45 
   46 -- |Accept a start and end point and return a list of points that draw a line to
   47 -- the endpoint. Note that this doesn't work for anything other than vertical,
   48 -- horizontal, and 45deg.
   49 lineTo :: Line -> [(Point, Sum Int)]
   50 lineTo ((x1, y1), (x2, y2)) = zipWith (curry (, Sum 1)) (range x1 x2) (range y1 y2)
   51   where range p1 p2 | p1 == p2  = repeat p1
   52                     | otherwise = p1 ~~ p2
   53 
   54 -- |Parse puzzle input into simple pairs of pairs of points.
   55 parseVents :: Text -> [Line]
   56 parseVents = fromRight . parseOnly parser
   57   where
   58     parser = line `sepBy1` endOfLine <* atEnd
   59     line  = (,) <$> point <* string " -> " <*> point
   60     point = (,) <$> decimal <* char ',' <*> decimal