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