67 lines
1.9 KiB
Haskell
67 lines
1.9 KiB
Haskell
import Prelude
|
|
import Data.List.Split (splitOn)
|
|
import qualified Data.Map.Lazy as M
|
|
import Data.Map.Lazy ((!))
|
|
|
|
data Tile = Wall | Sand
|
|
deriving (Eq)
|
|
|
|
type Pos = (Int, Int)
|
|
type Grid a = M.Map Pos a
|
|
|
|
(!!!) :: Grid a -> Pos -> a
|
|
(!!!) = (!)
|
|
|
|
-- parsing time...
|
|
|
|
writeWall :: Grid Tile -> [Pos] -> Grid Tile
|
|
writeWall startGrid positions = snd $ foldl (\(oldPos, grid) newPos -> (newPos, writeWall' grid (oldPos, newPos))) (head positions, startGrid) positions
|
|
where
|
|
writeWall' :: Grid Tile -> (Pos, Pos) -> Grid Tile
|
|
writeWall' grid ((x1, y1), (x2, y2)) = grid `M.union` wallsGrid
|
|
where
|
|
wallsGrid = M.fromList $ concatMap (\y -> map (\x -> ((x, y), Wall)) [minX .. maxX]) [minY .. maxY]
|
|
minX = min x1 x2
|
|
minY = min y1 y2
|
|
maxX = max x1 x2
|
|
maxY = max y1 y2
|
|
|
|
writeWalls :: [[Pos]] -> Grid Tile
|
|
writeWalls = foldl writeWall M.empty
|
|
|
|
parsePos :: String -> Pos
|
|
parsePos p = (read $ split !! 0, read $ split !! 1)
|
|
where split = splitOn "," p
|
|
|
|
parseWall :: String -> [Pos]
|
|
parseWall = map parsePos . splitOn " -> "
|
|
|
|
sandPos = (500, 0)
|
|
|
|
dropSand :: Grid Tile -> Maybe (Grid Tile)
|
|
dropSand grid = case sandGrain of
|
|
(Just pos) -> Just $ grid `M.union` M.singleton pos Sand
|
|
Nothing -> Nothing
|
|
where
|
|
sandGrain = resolveSand sandPos
|
|
maxY = maximum $ map snd $ M.keys grid
|
|
|
|
resolveSand :: Pos -> Maybe Pos
|
|
resolveSand (x, y)
|
|
| null validPositions = Just (x, y)
|
|
| y > maxY = Nothing
|
|
| otherwise = resolveSand $ head validPositions
|
|
where
|
|
validPositions = filter (not . (`M.member` grid)) [(x, y + 1), (x - 1, y + 1), (x + 1, y + 1)]
|
|
|
|
repeatUntilNothing :: (a -> Maybe a) -> a -> a -> a
|
|
repeatUntilNothing f previous input = case f input of
|
|
Just x -> repeatUntilNothing f input x
|
|
Nothing -> previous
|
|
|
|
main = interact $
|
|
show
|
|
. (+ 1) . length . M.filter (== Sand)
|
|
. (\grid -> repeatUntilNothing dropSand grid grid)
|
|
. writeWalls
|
|
. map parseWall . lines |