-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay4.hs
65 lines (50 loc) · 1.65 KB
/
Day4.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
module Day4 where
import Control.Applicative (many, some)
import Data.Fix (cata)
import Data.Functor.Base (ListF (..))
import qualified Data.IntMap as M
import Data.List (tails)
import Data.Monoid
import qualified Data.Set as S
import qualified Data.Text as T
import qualified Data.Text.IO as T
import Parser
import qualified Witherable as W
program :: FilePath -> IO ()
program = (=<<) print . fmap logic . T.readFile
data Answer = Answer Int Int deriving (Eq, Show)
logic :: T.Text -> Answer
logic = (Answer <$> answer1 <*> answer2) . parseInput
newtype CardId = CardId Int deriving (Eq, Show, Ord)
data Card = Card
{ cardId :: CardId
, winningNumbers :: S.Set Int
, numbers :: S.Set Int
}
deriving (Eq, Show)
answer1 :: [Card] -> Int
answer1 = getSum . foldMap (Sum . score)
winners :: Card -> S.Set Int
winners = S.intersection <$> winningNumbers <*> numbers
score :: Card -> Int
score = points . winners
where
points winning
| null winning = 0
| otherwise = 2 ^ (S.size winning - 1)
answer2 :: [Card] -> Int
answer2 = sum . fmap countAllCards . tails . fmap (S.size . winners)
countAllCards :: [Int] -> Int
countAllCards [_] = 1
countAllCards [] = 0
countAllCards (x:xs) = 1 + sum (fmap countAllCards $ take x $ tails xs)
parseInput :: T.Text -> [Card]
parseInput = W.mapMaybe (parseCard . T.unpack) . T.lines
parseCard :: String -> Maybe Card
parseCard = parseAll cardP
cardP :: Parser Card
cardP = Card <$> (string "Card" *> spaces *> cardIdP <* string ":" <* spaces) <*> numbersP <*> (string " |" *> spaces *> numbersP)
where
cardIdP = CardId <$> decimal
numbersP :: Parser (S.Set Int)
numbersP = fmap S.fromList (decimal `sepBy` many space)