Skip to content

Instantly share code, notes, and snippets.

@xpmatteo
Created June 19, 2015 10:33
Show Gist options
  • Save xpmatteo/0d93dd536c83470b91ff to your computer and use it in GitHub Desktop.
Save xpmatteo/0d93dd536c83470b91ff to your computer and use it in GitHub Desktop.
A solution to the water flow problem
data Tile = Rock | Air
type Stripe = [Tile]
type Heights = [Int]
type Water = Int
trimLeft :: Stripe -> Stripe
trimLeft [] = []
trimLeft (Air : xs) = trimLeft(xs)
trimLeft xs = xs
trimRight :: Stripe -> Stripe
trimRight = reverse . trimLeft . reverse
isAir Air = True
isAir Rock = False
waterInStripe :: Stripe -> Water
waterInStripe = length . (filter isAir) . trimRight . trimLeft
water :: Heights -> Water
water heights = sum (map (waterInStripe . stripe) [0..maximum(heights)])
where
stripe level = map (\height -> if level <= height then Rock else Air) heights
-- water [3,5,1,3,1,2,1,7,7,6] == 17
type LengthOfWaterPostfix = Int
waterInStripe1 :: Water -> LengthOfWaterPostfix -> Stripe -> Water
waterInStripe1 w p [] = w
waterInStripe1 w p (Rock:xs) = waterInStripe1 (w+p) 0 xs
waterInStripe1 w p (Air:xs) = waterInStripe1 w (p+1) xs
-- waterInStripe2 is a faster version of waterInStripe. It avoids calling "reverse".
waterInStripe2 :: Stripe -> Water
waterInStripe2 = (waterInStripe1 0 0) . trimLeft
-- water1 is a faster version of water
water1 :: Heights -> Water
water1 heights = sum (map (waterInStripe2 . stripe) [0..maximum(heights)])
where
stripe level = map (\height -> if level <= height then Rock else Air) heights
-- water1 [3,5,1,3,1,2,1,7,7,6] == 17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment