Created
December 3, 2018 21:12
-
-
Save zindel/31ca8cfad3887f304098643987afbfbf to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Data.Char | |
import qualified Data.Map as M | |
import qualified Data.Set as S | |
data Claim = Claim { elfId :: Int | |
, left :: Int | |
, top :: Int | |
, width :: Int | |
, height :: Int | |
} | |
deriving (Show) | |
data Token = IntT Int | |
| ClaimT Claim | |
type ParserState = ([Token], String) | |
type TokenStream = Either String ParserState | |
-- #166 @ 34,416: 22x15 | |
instance Read Claim where | |
readsPrec _ s = | |
case parsed of | |
Right([ClaimT claim], rest) -> [(claim, rest)] | |
Left _ -> [] | |
where | |
parsed = empty s | |
>>= skip "#" >>= parseInt | |
>>= skip " @ " >>= parseInt | |
>>= skip "," >>= parseInt | |
>>= skip ": " >>= parseInt | |
>>= skip "x" >>= parseInt | |
>>= parseClaim | |
empty :: String -> TokenStream | |
empty s = Right ([], s) | |
skip :: String -> ParserState -> TokenStream | |
skip s (tokens, rest) | |
| length s > length rest = Left "ended too early" | |
| all (uncurry (==)) $ zip s rest = Right (tokens, drop (length s) rest) | |
| otherwise = Left "pattern not found" | |
parseInt :: ParserState -> TokenStream | |
parseInt (tokens, rest) = | |
case takeWhile isDigit rest of | |
"" -> Left "bad int literal" | |
n -> Right (IntT(read n :: Int) : tokens, drop (length n) rest) | |
parseClaim :: ParserState -> TokenStream | |
parseClaim (tokens, rest) = | |
case tokens of | |
[IntT height, IntT width, IntT top, IntT left, IntT elfId] -> | |
let claim = Claim { elfId = elfId | |
, left = left | |
, top = top | |
, width = width | |
, height = height | |
} | |
in | |
Right ([ClaimT claim], rest) | |
_ -> Left "expected 5 ints" | |
squares :: Claim -> [(Int, Int)] | |
squares (Claim {left = left, top = top, width =width, height = height}) = | |
[(x,y) | x <- [left + 1 .. left + width], y <- [top + 1 .. top + height]] | |
solve1 :: [Claim] -> Int | |
solve1 = M.size . M.filter (> 1) . foldl processClaim M.empty | |
where processClaim m = foldl (\m sq -> M.insertWith (+) sq 1 m) m . squares | |
solve2 :: [Claim] -> S.Set Int | |
solve2 claims = S.difference (S.fromList $ map elfId claims) (overlaps claims) | |
where processClaim m claim = | |
foldl (\m sq -> M.insertWith S.union sq (S.singleton $ elfId claim) m) m | |
$ squares claim | |
overlaps = M.foldl S.union S.empty | |
. M.filter (\s -> S.size s > 1) | |
. foldl processClaim M.empty | |
input :: IO [Claim] | |
input = do | |
f <- readFile "day3.txt" | |
return $ map read $ lines f |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment