adventofcode/2022/day14.hs

55 lines
1.9 KiB
Haskell

import Data.List.Split (splitOn)
import qualified Data.Set as S
type Coord = (Int, Int)
readCoord :: String -> Coord
readCoord s = read ("(" ++ s ++ ")")
readLine :: String -> [Coord]
readLine xs = map readCoord (splitOn " -> " xs)
interpolate :: Coord -> Coord -> S.Set Coord
interpolate (a,b) (x,y)
| a == x && b == y = S.singleton (a,b)
| a == x && b < y = S.insert (a,b) (interpolate (a,b+1) (x,y))
| a == x && b > y = S.insert (a,b) (interpolate (a,b-1) (x,y))
| a < x && b == y = S.insert (a,b) (interpolate (a+1,b) (x,y))
| a > x && b == y = S.insert (a,b) (interpolate (a-1,b) (x,y))
interpolateLine :: [Coord] -> S.Set Coord
interpolateLine [x,y] = interpolate x y
interpolateLine (x:y:xs) = S.union (interpolate x y) (interpolateLine (y:xs))
part1 :: Coord -> S.Set Coord -> Int -> Int
part1 (x,y) occupied limit
| y > limit = 0
| S.notMember (x,y+1) occupied = part1 (x, y+1) occupied limit
| S.notMember (x-1, y+1) occupied = part1 (x-1, y+1) occupied limit
| S.notMember (x+1, y+1) occupied = part1 (x+1, y+1) occupied limit
| otherwise = 1 + part1 (500,0) (S.insert (x,y) occupied) limit
part2 :: Coord -> S.Set Coord -> Int -> Int
part2 (x,y) occupied limit
| S.member (500,0) occupied = 0
| y+1 == limit+2 = 1 + part2 (500,0) (S.insert (x,y) occupied) limit
| S.notMember (x,y+1) occupied = part2 (x, y+1) occupied limit
| S.notMember (x-1, y+1) occupied = part2 (x-1, y+1) occupied limit
| S.notMember (x+1, y+1) occupied = part2 (x+1, y+1) occupied limit
| otherwise = 1 + part2 (500,0) (S.insert (x,y) occupied) limit
main :: IO ()
main = do
x <- map readLine . lines <$> getContents
let rocks = foldr1 S.union (map interpolateLine x)
let start = (500,0)
let lowest = maximum (map snd (S.toList rocks))
putStr "part 1: "
print $ part1 (500,0) rocks lowest
putStr "part 2: "
print $ part2 (500,0) rocks lowest