-
Notifications
You must be signed in to change notification settings - Fork 0
/
DiamondSquare.elm
64 lines (61 loc) · 2.47 KB
/
DiamondSquare.elm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
module DiamondSquare exposing (diamondSquare)
import Array exposing (Array)
import Random
import Random.Array
import Lazy
diamondSquare : Int -> (Float,Float,Float,Float) -> Random.Generator (Array (Array Float))
diamondSquare detail corners =
Random.map
(diamondSquareLazy corners (2^detail+1)
>> Array.map (Array.map Lazy.force))
(Random.Array.array (2^detail+1)
<| Random.Array.array (2^detail+1)
<| Random.float -1 1)
diamondSquareLazy : (Float,Float,Float,Float) -> Int -> Array (Array Float) -> Array (Array (Lazy.Lazy Float))
diamondSquareLazy (a,b,c,d) size randomness =
let f : Int -> Int -> Float -> Lazy.Lazy Float
f x y rand =
if x == 0 && y == 0
then Lazy.lazy <| \_ -> a
else if x == 0 && y == size - 1
then Lazy.lazy <| \_ -> b
else if x == size - 1 && y == 0
then Lazy.lazy <| \_ -> c
else if x == size - 1 && y == size - 1
then Lazy.lazy <| \_ -> d
else
basedOn x y
|> (\(dist,diag) ->
if diag
then
( sqrt 2 * toFloat dist
, [(x+dist,y+dist)
,(x+dist,y-dist)
,(x-dist,y+dist)
,(x-dist,y-dist)])
else
( toFloat dist
, [(x+dist,y)
,(x-dist,y)
,(x,y+dist)
,(x,y-dist)]))
|> (\(scale,lst) -> Lazy.lazy (\_ ->
lst
|> List.filterMap
(\(x,y) ->
answer
|> Array.get x
|> Maybe.andThen (Array.get y)
|> Maybe.map Lazy.force)
|> (\nearby -> List.sum nearby / toFloat (List.length nearby))
|> (+) (rand * scale / toFloat size)))
answer : Array (Array (Lazy.Lazy Float))
answer = Array.indexedMap (\x -> Array.indexedMap (\y -> f x y)) randomness
basedOn : Int -> Int -> (Int,Bool)
basedOn x y =
case (x % 2, y % 2) of
(0,0) -> Tuple.mapFirst ((*) 2) <| basedOn (x//2) (y//2)
(0,_) -> (1,False)
(_,0) -> (1,False)
(_,_) -> (1,True)
in answer