Given a map of the area, represented by a rectangular matrix of heights (for example, integers). From each cell, water will drain into one of the neighboring cells (north, east, south, west) with the lowest height if
it is less than the height of this cell. Otherwise, this cell is called a drain. It is necessary to mark equally all the cells of the map, the water from which will flow into the same drain.
drainOf cell = case lowestNeighbourOf cell of Nothing → cell Just nb → drainOf nb
print (drainOf cell) print (drainOf cell)
let drain = drainOf cell print drain print drain
cells = ((1,1), (width, height)) altitude :: (int, int) → int - here it is, an array of drains of all cells! But it is calculated lazily - i.e. for now this is only a list of calls to the drainOf function, but not its results. drains = array cells [(cell, drainOf cell) | cell ← range cells] drainOf cell = case lowestNeighbourOf cell of Nothing → cell Just nb → drains! nb - appeal to the element of the array of stocks - here at the first call, the calculation of drainOf will occur, - and at the second - the return of the cached result lowestNeighbourOf (x, y) = let neighbors = filter (inRange cells) [ (x, y-1), (x + 1, y), (x, y + 1), (x-1, y)] lowest = minimumBy (compare`on`altitude) neighbors in if altitude lowest ≥ altitude (x, y) then Nothing else just lowest
import Data.Array import Debug.Trace (trace) import Control.Monad (forM_) import Data.List (minimumBy, transpose) import Data.Function (on) - simple data - cells = ((1,1), (3,3)) altitudes = listArray cells $ concat $ transpose [ [10, 8, 10], [15, 3, 15], [20, 25, 20]] - common functions - altitude :: (int, int) → int altitude cell = altitudes! cell lowestNeighbourOf (x, y) = let neighbors = filter (inRange cells) [ (x, y-1), (x + 1, y), (x, y + 1), (x-1, y)] lowest = minimumBy (compare`on`altitude) neighbors in if altitude lowest ≥ altitude (x, y) then Nothing else just lowest printArray arr = let ((sx, sy), (ex, ey)) = bounds arr printRow y = forM_ [sx..ex] (λ x → putStr (show (arr! (x, y)) ++ "\ t")) in forM_ [sy..ey] (λ y → printRow y "putStrLn" ") main = do printArray altitudes putStrLn "- drains -------------" printArray drains putStrLn "- drains ′ ------------" printArray drains ′ - simple recursion - drains = array cells [(cell, drainOf cell) | cell ← range cells] drainOf cell | trace ("drainOf" ++ show cell) False = undefined drainOf cell = case lowestNeighbourOf cell of Nothing → cell Just nb → drainOf nb - lazy caching - drains ′ = array cells [(cell, drainOf ′ cell) | cell ← range cells] drainOf ′ cell | trace ("drainOf ′" ++ show cell) False = undefined drainOf ′ cell = case lowestNeighbourOf cell of Nothing → cell Just nb → drains ′! nb
10 8 10 15 3 15 20 25 20 - drains ------------- drainOf (1,1) drainOf (2.1) drainOf (2.2) drainOf (2.1) drainOf (2.2) drainOf (3.1) drainOf (2.1) drainOf (2.2) (2.2) (2.2) (2.2) drainOf (1,2) drainOf (2.2) drainOf (2.2) drainOf (3.2) drainOf (2.2) (2.2) (2.2) (2.2) drainOf (1,3) drainOf (1,2) drainOf (2.2) drainOf (2,3) drainOf (2.2) drainOf (3.3) drainOf (3.2) drainOf (2.2) (2.2) (2.2) (2.2) - drains' ------------ drainOf '(1,1) drainOf '(2,1) drainOf (2.2) drainOf '(3,1) (2.2) (2.2) (2.2) drainOf (1,2) drainOf '(3,2) (2.2) (2.2) (2.2) drainOf (1,3) drainOf (2,3) drainOf '(3.3) (2.2) (2.2) (2.2)
Source: https://habr.com/ru/post/130945/
All Articles