module AOC.Challenge.Day03 (
day03a
, day03b
) where
import AOC.Common (freqs, findMaybe, clearOut)
import AOC.Solver ((:~>)(..))
import Control.Monad (guard)
import Data.Char (isDigit)
import Data.Ix (range)
import Data.Map (Map)
import Data.Maybe (mapMaybe)
import Linear (V2(..))
import Text.Read (readMaybe)
import qualified Data.Map as M
type Coord = V2 Int
data Claim = C { _cId :: Int
, _cRect :: Rect
}
data Rect = R { _rStart :: Coord
, _rSize :: Coord
}
parseLine :: String -> Maybe Claim
parseLine = mkLine
. mapMaybe readMaybe
. words
. clearOut (not . isDigit)
where
mkLine [i,x0,y0,w,h] = Just $ C i (R (V2 x0 y0) (V2 w h))
mkLine _ = Nothing
tiles :: Rect -> [Coord]
tiles (R start size) = range (start, start + size - 1)
layTiles :: [Rect] -> Map Coord Int
layTiles = freqs . concatMap tiles
day03a :: [Rect] :~> Int
day03a = MkSol
{ sParse = traverse (fmap _cRect . parseLine) . lines
, sShow = show
, sSolve = Just
. length
. filter (>= 2)
. M.elems
. layTiles
}
day03b :: [Claim] :~> Int
day03b = MkSol
{ sParse = traverse parseLine . lines
, sShow = show
, sSolve = \ts ->
let tilesClaimed = layTiles (_cRect <$> ts)
in findMaybe (noOverlap tilesClaimed) ts
}
noOverlap
:: Map Coord Int
-> Claim
-> Maybe Int
noOverlap tilesClaimed C{..} = _cId <$ guard (all isAlone (tiles _cRect))
where
isAlone c = M.lookup c tilesClaimed == Just 1