Renames rect to claim

master
Abhinav Sarkar 2018-12-27 15:53:08 +05:30
parent 780d339a68
commit 1095c18980
1 changed files with 62 additions and 58 deletions

120
3/3.hs
View File

@ -10,64 +10,68 @@ import Data.List (maximumBy, foldl', sort, sortOn)
import Data.Ord (comparing) import Data.Ord (comparing)
import Text.Parsec hiding (Empty) import Text.Parsec hiding (Empty)
data Rect = Rect { rectID :: Int data Claim = Claim { claimID :: Int
, rectLeft :: Int , claimLeft :: Int
, rectTop :: Int , claimTop :: Int
, rectWidth :: Int , claimWidth :: Int
, rectHeight :: Int , claimHeight :: Int
} }
instance Eq Rect where instance Eq Claim where
(==) = (==) `on` rectID (==) = (==) `on` claimID
instance Ord Rect where instance Ord Claim where
compare = compare `on` rectID compare = compare `on` claimID
instance Show Rect where instance Show Claim where
show (Rect id l t w h) = "#" ++ show id ++ " " ++ show l ++ "," ++ show t ++ ":" ++ show (l+w) ++ "," ++ show (t+h) show (Claim id l t w h) =
"<#" ++ show id ++ " "
++ "(" ++ show l ++ "," ++ show t ++ ")-"
++ "(" ++ show (l+w) ++ "," ++ show (t+h) ++ ")>"
inputP :: Parsec String () Rect claimParser :: Parsec String () Claim
inputP = claimParser =
(\id (l,t) (w,h) -> Rect id l t w h) (\id (l,t) (w,h) -> Claim id l t w h)
<$> (idP <* spaces <* char '@' <* spaces) <$> (idP <* spaces <* char '@' <* spaces)
<*> (posP <* char ':' <* spaces) <*> (posP <* char ':' <* spaces)
<*> dimP <*> dimP
where where
intP = read <$> some digit intP = read <$> some digit
idP = char '#' *> intP idP = char '#' *> intP
posP = (,) <$> (intP <* char ',') <*> intP posP = (,) <$> (intP <* char ',') <*> intP
dimP = (,) <$> (intP <* char 'x') <*> intP dimP = (,) <$> (intP <* char 'x') <*> intP
readInput :: [String] -> [Rect] readInput :: String -> [Claim]
readInput ls = case traverse (parse inputP "") ls of readInput input = case traverse (parse claimParser "") $ lines input of
Left e -> error (show e) Left e -> error (show e)
Right rs -> rs Right rs -> rs
sheetSize :: [Rect] -> (Int, Int) sheetSize :: [Claim] -> (Int, Int)
sheetSize rects = sheetSize claims = (calcBound claimRight, calcBound claimBottom)
( calcBound (\(Rect _ l _ w _) -> l + w)
, calcBound (\(Rect _ _ t _ h) -> t + h))
where where
calcBound f = f (maximumBy (comparing f) rects) claimRight (Claim _ l _ w _) = l + w
claimBottom (Claim _ _ t _ h) = t + h
calcBound f = f (maximumBy (comparing f) claims)
isOverlapCell :: [Rect] -> (Int, Int) -> Bool isOverlapCell :: [Claim] -> (Int, Int) -> Bool
isOverlapCell rects cell = isOverlapCell claims cell =
(> 1) . length . take 2 . filter (cellInRect cell) $ rects (> 1) . length . filter (cellInClaim cell) $ claims
where where
cellInRect (x, y) (Rect _ l t w h) = cellInClaim (x, y) (Claim _ l t w h) =
l <= x && (l+w) >= (x+1) && t <= y && (t+h) >= (y+1) l <= x && (l+w) >= (x+1) && t <= y && (t+h) >= (y+1)
---------------- Brute force ---------------- ---------------- Brute force ----------------
bruteForceSolve :: [Rect] -> (Int, [Rect]) bruteForceSolve :: [Claim] -> (Int, [Claim])
bruteForceSolve rects = bruteForceSolve claims =
let (w, h) = sheetSize rects let (width, height) = sheetSize claims
cells = [(i, j) | i <- [0..w-1], j <- [0..h-1]] cells = [(i, j) | i <- [0..width-1], j <- [0..height-1]]
overlapArea = length . filter (isOverlapCell rects) $ cells overlapArea = length . filter (isOverlapCell claims) $ cells
noOverlapRects = filter (\r -> not $ any (\r1 -> r1 /= r && r1 `overlaps` r) rects) rects noOverlapClaims =
in (overlapArea, noOverlapRects) filter (\c -> not $ any (\c' -> c' /= c && c' `overlaps` c) claims) claims
in (overlapArea, noOverlapClaims)
where where
(Rect _ l1 t1 w1 h1) `overlaps` (Rect _ l2 t2 w2 h2) = (Claim _ l1 t1 w1 h1) `overlaps` (Claim _ l2 t2 w2 h2) =
l1 < (l2+w2) && (l1+w1) > l2 && t1 < (t2+h2) && (t1+h1) > t2 l1 < (l2+w2) && (l1+w1) > l2 && t1 < (t2+h2) && (t1+h1) > t2
---------------- Interval tree ---------------- ---------------- Interval tree ----------------
@ -132,44 +136,44 @@ intersectingIntervals =
fromList :: (Ord a, Ord b, Bits a, Num a) => a -> a -> [(Interval a, b)] -> IntervalTree a b fromList :: (Ord a, Ord b, Bits a, Num a) => a -> a -> [(Interval a, b)] -> IntervalTree a b
fromList start end = foldl' (flip insert) (Empty start end) fromList start end = foldl' (flip insert) (Empty start end)
toInterval :: (Rect -> Int) -> (Rect -> Int) -> Rect -> Interval Int toInterval :: (Claim -> Int) -> (Claim -> Int) -> Claim -> Interval Int
toInterval pos dim rect = Interval (pos rect, pos rect + dim rect) toInterval pos dim claim = Interval (pos claim, pos claim + dim claim)
rectIntervalTrees :: [Rect] -> (IntervalTree Int Rect, IntervalTree Int Rect) claimIntervalTrees :: [Claim] -> (IntervalTree Int Claim, IntervalTree Int Claim)
rectIntervalTrees rects = claimIntervalTrees claims =
let (w, h) = sheetSize rects let (w, h) = sheetSize claims
in ( fromList 0 w . map (\r -> (toInterval rectLeft rectWidth r, r)) $ rects in ( fromList 0 w . map (\c -> (toInterval claimLeft claimWidth c, c)) $ claims
, fromList 0 h . map (\r -> (toInterval rectTop rectHeight r, r)) $ rects , fromList 0 h . map (\c -> (toInterval claimTop claimHeight c, c)) $ claims
) )
toTree :: (Show a, Show b) => IntervalTree a b -> T.Tree String toTree :: (Show a, Show b) => IntervalTree a b -> T.Tree String
toTree (Empty start end) = T.Node (show ("E", start, end)) [] toTree (Empty start end) = T.Node (show ("E", start, end)) []
toTree (Node l c is _ r) = T.Node (show ("N", c, is)) [toTree l, toTree r] toTree (Node l c is _ r) = T.Node (show ("N", c, is)) [toTree l, toTree r]
intervalTreeSolve :: [Rect] -> (Int, [Rect]) intervalTreeSolve :: [Claim] -> (Int, [Claim])
intervalTreeSolve rects = intervalTreeSolve claims =
let (w, h) = sheetSize rects let (w, h) = sheetSize claims
cells = [(i, j) | i <- [0..w-1], j <- [0..h-1]] cells = [(i, j) | i <- [0..w-1], j <- [0..h-1]]
(xTree, yTree) = rectIntervalTrees rects (xTree, yTree) = claimIntervalTrees claims
overlapArea = length . filter (\c -> isOverlapCell (cellRects xTree yTree c) c) $ cells overlapArea = length . filter (\c -> isOverlapCell (cellClaims xTree yTree c) c) $ cells
noOverlapRects = filter ((== 1) . Set.size . overlappingRects xTree yTree) rects noOverlapClaims = filter ((== 1) . Set.size . overlappingClaims xTree yTree) claims
in (overlapArea, noOverlapRects) in (overlapArea, noOverlapClaims)
where where
cellRects xTree yTree (x,y) = cellClaims xTree yTree (x,y) =
nub . map snd nub . map snd
$ includingIntervals (Interval (x, x+1)) xTree ++ includingIntervals (Interval (y, y+1)) yTree $ includingIntervals (Interval (x, x+1)) xTree ++ includingIntervals (Interval (y, y+1)) yTree
nub = Set.toList . Set.fromList nub = Set.toList . Set.fromList
rectIntervals tree pos dim rect = claimIntervals tree pos dim claim =
Set.fromList . map snd . intersectingIntervals (toInterval pos dim rect) $ tree Set.fromList . map snd . intersectingIntervals (toInterval pos dim claim) $ tree
overlappingRects xTree yTree rect = overlappingClaims xTree yTree claim =
rectIntervals xTree rectLeft rectWidth rect `Set.intersection` rectIntervals yTree rectTop rectHeight rect claimIntervals xTree claimLeft claimWidth claim `Set.intersection` claimIntervals yTree claimTop claimHeight claim
main :: IO () main :: IO ()
main = do main = do
rects <- readInput . lines <$> getContents claims <- readInput <$> getContents
let (overlapArea, noOverlapRects) = intervalTreeSolve rects let (overlapArea, noOverlapClaims) = intervalTreeSolve claims
putStrLn $ "Overlap Area = " ++ show overlapArea putStrLn $ "Overlap Area = " ++ show overlapArea
putStrLn $ "No overlap rects = " ++ show noOverlapRects putStrLn $ "No overlap claims = " ++ show noOverlapClaims