day 15 part 2
This commit is contained in:
parent
1c778caeb2
commit
05a81eb063
|
|
@ -1,11 +1,17 @@
|
|||
import Data.List.Split (splitOn)
|
||||
import qualified Data.Set as S
|
||||
import Data.List (sortOn, sort)
|
||||
import qualified Data.Map as M
|
||||
import Debug.Trace (traceShowId)
|
||||
import GHC.Utils.GlobalVars (global)
|
||||
|
||||
type Coord = (Int, Int)
|
||||
|
||||
globalY :: Int
|
||||
globalY = 2000000
|
||||
|
||||
bound = 4000000
|
||||
|
||||
parseCoord :: String -> Coord
|
||||
parseCoord xs = (read $ init x, read y) where
|
||||
[x,y] = map (drop 2) $ splitOn " " xs
|
||||
|
|
@ -17,23 +23,86 @@ parseLine xs = (sensor, beacon) where
|
|||
manhattan :: Coord -> Coord -> Int
|
||||
manhattan (a,b) (x,y) = abs (a-x) + abs (b-y)
|
||||
|
||||
allWithinRange :: Coord -> Coord -> S.Set Coord
|
||||
allWithinRange sensor@(a,b) beacon@(x,y) = S.fromList $ filter (\c -> manhattan sensor c <= dist) all where
|
||||
allWithinRange :: Coord -> Coord -> Int -> [Coord]
|
||||
allWithinRange sensor@(a,b) beacon@(x,y) row = filter (\c -> manhattan sensor c <= dist) all where
|
||||
minx = a - dist
|
||||
maxx = a + dist
|
||||
miny = b - dist
|
||||
maxy = b + dist
|
||||
dist = manhattan sensor beacon
|
||||
all = [(x,y) | x <- [minx..maxx], y <- [globalY]]
|
||||
all = [(x,row) | x <- [minx..maxx]]
|
||||
|
||||
closest :: Coord -> M.Map Coord Int -> Coord
|
||||
closest coord beacons = closest -- manhattan coord closest > beacons M.! closest
|
||||
where
|
||||
closest = head $ sortOn (manhattan coord) (M.keys beacons)
|
||||
|
||||
scan :: M.Map Coord Int -> Coord -> Coord
|
||||
scan dists progress@(x,y)
|
||||
| outOfRange = progress
|
||||
| x > bound = scan dists $ if y `mod` 1000 == 0 then traceShowId (0,y+1) else (0, y+1)
|
||||
| y > bound = error "no beacon"
|
||||
| x < fst near = scan dists (fst near + abs xdist, y)
|
||||
| otherwise = scan dists (x+1, y)
|
||||
where
|
||||
near = closest progress dists
|
||||
outOfRange = all (\(sensor, dist) -> manhattan sensor progress > dist) (M.toList dists)
|
||||
xdist = x - fst near
|
||||
next = if x < fst near then (fst near + xdist, y) else (x + 1, y)
|
||||
|
||||
bounds :: Coord -> Coord -> Int -> [(Int, Int)]
|
||||
bounds sensor@(x,y) coord@(a,b) row = [(x - xdist, x + xdist) | ydist <= dist] where
|
||||
dist = manhattan sensor coord
|
||||
ydist = abs (y-row)
|
||||
xdist = (dist - ydist)
|
||||
|
||||
mergeBounds :: [(Int, Int)] -> [(Int, Int)]
|
||||
mergeBounds [x] = [x]
|
||||
mergeBounds ((a,b):(x,y):xs)
|
||||
| maxL >= minR - 1 = mergeBounds $ (minTot, maxTot):xs
|
||||
| otherwise = [(a,b), (x,y)]
|
||||
where
|
||||
minL = min a b
|
||||
maxL = max a b
|
||||
minR = min x y
|
||||
maxR = max x y
|
||||
minTot = min minL minR
|
||||
maxTot = max maxL maxR
|
||||
|
||||
traceCond :: (Int, Int) -> (Int, Int)
|
||||
traceCond (x,y) = if x `mod` 1000 == 0 && y `mod` 1000 == 0 then traceShowId (x,y) else (x,y)
|
||||
|
||||
scan' :: [(Coord, Coord)] -> M.Map Coord Int -> Coord -> Coord
|
||||
scan' input dists progress@(x,y)
|
||||
| length covered == 1 && fst (head covered) <= 0 && snd (head covered) >= bound = scan' input dists $ traceCond (0, y+1)
|
||||
| outOfRange = progress
|
||||
| x > bound = scan' input dists $ traceShowId (0,y+1)
|
||||
| y > bound = error "no beacon"
|
||||
| otherwise = scan' input dists $ traceCond (x+1, y)
|
||||
-- | x < fst near = scan' input dists $ traceShowId (fst near + abs xdist, y)
|
||||
-- | otherwise = scan' input dists $ traceShowId (x+1, y)
|
||||
where
|
||||
covered = mergeBounds $ sort $ concatMap (\(s,b) -> bounds s b y) input
|
||||
near = closest progress dists
|
||||
outOfRange = all (\(sensor, dist) -> manhattan sensor progress > dist) (M.toList dists)
|
||||
xdist = x - fst near
|
||||
next = if x < fst near then (fst near + xdist, y) else (x + 1, y)
|
||||
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
x <- map parseLine . lines <$> getContents
|
||||
|
||||
let beacons = S.fromList $ map snd x
|
||||
let reachable = foldr1 S.union $ map (uncurry allWithinRange) x
|
||||
let reachable = foldr1 S.union $ map (\(a,b) -> S.fromList $ allWithinRange a b globalY) x
|
||||
|
||||
let dists = M.fromList $ map (\(s,b) -> (s, manhattan s b)) x
|
||||
|
||||
let ys = S.size $ S.filter (\x -> snd x == globalY) (reachable S.\\ beacons)
|
||||
|
||||
putStr "part 1: "
|
||||
print ys
|
||||
-- putStr "part 1: "
|
||||
-- print ys
|
||||
|
||||
putStr "part 2: "
|
||||
let (x',y') = scan' x dists (0,3040754)
|
||||
print $ y' + x'*4000000
|
||||
Loading…
Reference in New Issue