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