48 lines
1.3 KiB
Haskell
48 lines
1.3 KiB
Haskell
import Aoc
|
|
import Data.List.Split ( splitOn )
|
|
import Data.Char ( isDigit )
|
|
import Control.Arrow ( second )
|
|
import Data.Maybe ( fromMaybe )
|
|
|
|
parseLine :: String -> (Int, [(String, Int)])
|
|
parseLine line =
|
|
let ("Sue ", rest0) = splitAt 4 line in
|
|
let (n, rest1) = span isDigit rest0 in
|
|
let (':':' ':rest2) = rest1 in
|
|
let items = splitOn ", " rest2 in
|
|
(read n, map (second read . pair . splitOn ": ") items)
|
|
|
|
tape :: [(String, Int)]
|
|
tape = [
|
|
("children", 3),
|
|
("cats", 7),
|
|
("samoyeds", 2),
|
|
("pomeranians", 3),
|
|
("akitas", 0),
|
|
("vizslas", 0),
|
|
("goldfish", 5),
|
|
("trees", 3),
|
|
("cars", 2),
|
|
("perfumes", 1)
|
|
]
|
|
|
|
part1' :: (String -> Int -> Int -> Bool) -> [(Int, [(String, Int)])] -> Int
|
|
part1' predicate = fst . single . filter matches
|
|
where matches (_, items) = all itemMatches tape
|
|
where itemMatches (name, n) = case lookup name items of
|
|
Nothing -> True
|
|
Just n' -> predicate name n' n
|
|
|
|
part1 :: [(Int, [(String, Int)])] -> Int
|
|
part1 = part1' $ const (==)
|
|
|
|
part2 :: [(Int, [(String, Int)])] -> Int
|
|
part2 = part1' $ fromMaybe (==) . flip lookup [
|
|
("cats", (>)),
|
|
("trees", (>)),
|
|
("pomeranians", (<)),
|
|
("goldfish", (<))
|
|
]
|
|
|
|
main :: IO ()
|
|
main = aocMain (map parseLine) part1 part2 |