1 import qualified Data.Map.Strict as M
2 import Text.ParserCombinators.ReadP
5 claims <- map parseClaim <$> lines <$> getContents
6 let layout = claimOverlap claims
7 let counts = M.fromListWith (+) . map (\v -> (v,1)) . M.elems $ layout
8 print $ counts M.! (-1)
9 print . index . claimUnoverlapped counts $ claims
11 data Claim = Claim { index :: Int
16 type ClaimMap = M.Map (Int, Int) Int
18 claimOverlap :: [Claim] -> ClaimMap
19 claimOverlap = foldl go M.empty . map claimedAreas
20 where cc :: Int -> Int -> Int
22 mn :: ClaimMap -> (Int, (Int, Int)) -> ClaimMap
23 mn cmap (v, k) = M.insertWith cc k v cmap
24 go :: ClaimMap -> [(Int, (Int, Int))] -> ClaimMap
25 go cmap = foldl mn cmap
27 claimUnoverlapped :: M.Map Int Int -> [Claim] -> Claim
28 claimUnoverlapped counts = head . filter go
29 where go :: Claim -> Bool
30 go (Claim ind _ (sx, sy)) =
31 (Just (sx*sy)) == counts M.!? ind
33 claimedAreas :: Claim -> [(Int, (Int, Int))]
34 claimedAreas (Claim ind (cx, cy) (sx, sy)) =
35 [(ind,(i,j)) | i <- [cx+1..cx+sx], j <- [cy+1..cy+sy]]
37 parseClaim :: String -> Claim
38 parseClaim = fst . head . readP_to_S go
39 where digit :: ReadP Char
40 digit = satisfy (\char -> char >= '0' && char <= '9')
44 ind <- read <$> many1 digit
46 cx <- read <$> many1 digit
48 cy <- read <$> many1 digit
50 sx <- read <$> many1 digit
52 sy <- read <$> many1 digit
54 return (Claim ind (cx, cy) (sx, sy))
56 countV :: Eq a => a -> [a] -> Int
57 countV val = length . filter (== val)