Skip to content

Instantly share code, notes, and snippets.

@rpglover64
Created November 11, 2013 13:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rpglover64/7412884 to your computer and use it in GitHub Desktop.
Save rpglover64/7412884 to your computer and use it in GitHub Desktop.
{-# LANGUAGE TupleSections #-}
module Waterflow
where
import Control.Applicative
import Data.Map (Map)
import qualified Data.Map as M
import Test.QuickCheck
water = sum $
zipWith (-)
(zipWith min (scanl1 max h) (scanr1 max h))
h
newtype Small a = Small {unSmall :: a}
instance Show a => Show (Small a) where
show = show
showsPrec = showsPrec
instance Arbitrary a => Arbitrary (Small a) where
arbitrary = sized $ \s -> Small <$> resize (s `div` 6) arbitrary
shrink (Small a) = Small <$> shrink a
prop_water_equal (NonEmpty ys) = water xs == trivialWater xs
where xs :: [Int]
xs = unSmall <$> ys
data Cell = Dirt | Water
deriving (Eq, Show)
trivialWaterMap xs = fst $ head $ dropWhile (uncurry (/=)) (zip steps $ tail steps)
where groundLevel = minimum xs
ys = concat [(,i) <$> [x, x-1 .. groundLevel] | (i,x) <- zip [0..] xs]
dirtMap = M.fromList $ map (,Dirt) ys
(rows, cols) = (maximum xs, length xs)
zs = [(r,c) | r <- [groundLevel .. rows], c <- [0 .. cols - 1]]
waterMap = M.fromList $ map (,Water) zs
initialMap = dirtMap `M.union` waterMap
steps = iterate (flowAll zs) initialMap
trivialWater = M.foldl inc 0 . trivialWaterMap
where inc acc v = case v of
Water -> acc + 1
Dirt -> acc
flow m loc cell = case cell of
Dirt -> Just Dirt
Water -> Water <$ (find (succ <$> loc) >> find (pred <$> loc))
where find = (`M.lookup` m)
flowAll ks m = foldl (flip $ M.updateWithKey (flow m)) m ks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment