X-Git-Url: https://git.njae.me.uk/?p=advent-of-code-22.git;a=blobdiff_plain;f=advent15%2FMainOriginal.hs;fp=advent15%2FMainOriginal.hs;h=d04b1eacbd9468bf608f52b3406e2035c8e8137b;hp=0000000000000000000000000000000000000000;hb=ef8354646420ae6364603d2fea33955cf87c3a53;hpb=89eb500db478502b125606aa4ffbf8c2cc515ddf diff --git a/advent15/MainOriginal.hs b/advent15/MainOriginal.hs new file mode 100644 index 0000000..d04b1ea --- /dev/null +++ b/advent15/MainOriginal.hs @@ -0,0 +1,91 @@ +-- Writeup at https://work.njae.me.uk/2022/12/15/advent-of-code-2022-day-15/ + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take, D) +import Data.Ix +import qualified Data.Set as S +import Linear hiding (Trace, trace, distance) + +type Position = V2 Int + +data Sensor = Sensor Position Position -- sensor position, beacon position + deriving (Eq, Show) + +newtype Region = Region { getRegion :: Position -> Bool } + +instance Semigroup Region where + r1 <> r2 = Region (\p -> getRegion r1 p || getRegion r2 p) + +instance Monoid Region where + -- mempty = Region (\p -> False) + mempty = Region (const False) + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let sensors = successfulParse text + -- print sensors + print $ part1 sensors + print $ part2 sensors + +thisY :: Int +-- thisY = 10 +thisY = 2000000 + +searchRange :: (Position, Position) +-- searchRange = ((V2 0 0), (V2 20 20)) +searchRange = ((V2 0 0), (V2 4000000 4000000)) + +part1, part2 :: [Sensor] -> Int +part1 sensors = length $ filter (\p -> p `notElem` occupied) $ filter (getRegion coverage) rowCoords + where coverage = mconcat $ fmap nearby sensors + rowCoords = range ((V2 (globalMinX sensors) thisY), (V2 (globalMaxX sensors) thisY)) + occupied = concatMap (\(Sensor s b) -> [s, b]) sensors + +part2 sensors = x * 4000000 + y + where coverage = mconcat $ fmap nearby sensors + boundaries = {-# SCC boundaries #-} S.filter (inRange searchRange) $ S.unions $ fmap justOutside sensors + V2 x y = {-# SCC findMinV #-} S.findMin $ S.filter (not . (getRegion coverage)) boundaries + +manhattan :: Position -> Position -> Int +manhattan p1 p2 = (abs dx) + (abs dy) + where V2 dx dy = p1 ^-^ p2 + +nearby :: Sensor -> Region +nearby (Sensor s b) = Region (\p -> manhattan s p <= dist) + where dist = manhattan s b + +minX, maxX :: Sensor -> Int +minX (Sensor s@(V2 sx _) b) = sx - (manhattan s b) +maxX (Sensor s@(V2 sx _) b) = sx + (manhattan s b) + +globalMinX, globalMaxX :: [Sensor] -> Int +globalMinX = minimum . fmap minX +globalMaxX = maximum . fmap maxX + +justOutside :: Sensor -> S.Set Position +justOutside (Sensor s@(V2 sx sy) b) = S.fromList (topLeft ++ topRight ++ bottomLeft ++ bottomRight) + where d = 1 + manhattan s b + topLeft = [V2 x y | (x, y) <- zip [(sx - d)..sx] [sy..(sy + d)] ] + topRight = [V2 x y | (x, y) <- zip [(sx + d), (sx + d - 1)..sx] [sy..(sy + d)] ] + bottomLeft = [V2 x y | (x, y) <- zip [(sx - d)..sx] [sy, (sy - 1)..(sy - d)] ] + bottomRight = [V2 x y | (x, y) <- zip [(sx + d), (sx + d - 1)..sx] [sy, (sy - 1)..(sy - d)] ] + +-- Parse the input file + +sensorsP :: Parser [Sensor] +sensorP :: Parser Sensor +positionP :: Parser Position + +sensorsP = sensorP `sepBy` endOfLine +sensorP = Sensor <$> ("Sensor at " *> positionP) <*> (": closest beacon is at " *> positionP) +positionP = V2 <$> (("x=" *> signed decimal) <* ", ") <*> ("y=" *> signed decimal) + +successfulParse :: Text -> [Sensor] +successfulParse input = + case parseOnly sensorsP input of + Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err + Right sensors -> sensors