-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPathFollowing.elm
150 lines (127 loc) · 4.39 KB
/
PathFollowing.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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
module PathFollowing exposing (..)
import ClassicalEngine exposing (Actor, stepActor, drawVehicle)
import Grid exposing (Grid, GridNode(..), Point, Path,
grid2screen, screen2grid, neighbors8, drawGrid)
import ChaseEvade exposing (chase, arrive, drawTarget)
import PathFinding exposing (AStarState,
initSearch, aStar, drawPath, drawRunningCosts)
import Random exposing (Seed, Generator, generate)
import Random.Array exposing (shuffle)
import Time exposing (Time, inSeconds)
import Color exposing (Color, yellow, green, red, grey)
import Collage exposing (Form, circle, solid, filled, move, collage)
import Array exposing (slice)
import Html exposing (Html)
import Element exposing (toHtml)
import List.Extra as List
--- CONSTANTS ---
-- (mostly) --
gridW : Int
gridW = 20
gridH : Int
gridH = 20
spacing : Float
spacing = 30
maxV : GridNode -> Float
maxV node = case node of
Obstacle -> 5
_ -> 80 / Grid.cost node
maxA : Float
maxA = 280
numExplorers : Int
numExplorers = 15
--- STRUCTURES ---
type Action = Init Simulation | Tick Time | Plot Point
type Exploration = Plotting Point | Seeking Path | Arriving Point | Resting
type alias SearchState etc = { etc
| state : Exploration
}
type alias Explorer etc = Actor (SearchState etc)
type alias Simulation =
{ grid : Grid
, explorers : List (Explorer {})
}
sim0 : Simulation
sim0 = { grid = Grid.grid0, explorers = [] }
--- BEHAVIOR ---
explore : Grid -> Explorer etc -> Explorer etc
explore grid e = let
p = screen2grid e.pos grid
node = Grid.get p grid
in case e.state of
Plotting goal -> { e | state = Seeking (aStar neighbors8 grid p goal) }
Seeking [] -> { e | state = Resting }
Seeking [goal] -> { e | state = Arriving goal }
Seeking (next :: rest) -> let path = next :: rest in
case List.dropWhile ((/=) p) path of
[] -> e |> chase (maxV node) maxA (grid2screen next grid)
[goal] -> { e | state = Arriving goal }
_ :: truncatedPath -> { e | state = Seeking truncatedPath }
Arriving goal -> if p == goal
then { e | state = Resting }
else e |> arrive (maxV node) maxA (grid2screen goal grid)
Resting -> e |> arrive (maxV node) maxA (grid2screen p grid)
--- SIMULATION ---
initSim : Generator Simulation
initSim = let
genGrid = Grid.random gridW gridH spacing
genIndices = shuffle (Array.initialize (gridW * gridH) identity)
in
Random.map2 (\grid indices -> let
openIndices = Array.filter
(\i -> Array.get i grid.array /= Just Obstacle) indices
points = Array.toList openIndices |> List.take numExplorers
|> List.map ((flip Grid.deindex) grid)
in
{ grid = grid
, explorers = List.map (\p ->
{ pos = grid2screen p grid
, v = (0, 0)
, a = (0, 0)
, state = Resting
}
) points
}
) genGrid genIndices
simulate : Time -> Simulation -> (Simulation, Cmd Action)
simulate t sim = let
dt = inSeconds t
(new_explorers, cmd) = List.foldr (\e (list, cmd) -> let
node = Grid.get (screen2grid e.pos sim.grid) sim.grid
new_e = e |> stepActor (maxV node) dt |> explore sim.grid
in (new_e :: list, case new_e.state of
Resting -> Random.generate Plot (Grid.samplePoint sim.grid)
_ -> cmd
)
) ([], Cmd.none) sim.explorers
in ({ sim | explorers = new_explorers }, cmd)
startPlot : Point -> Simulation -> Simulation
startPlot goal sim = { sim | explorers =
fst <| List.foldr (\e (es, done) ->
if not done && e.state == Resting
then ({ e | state = Plotting goal } :: es, True)
else (e :: es, done)
) ([], False) sim.explorers }
update : Action -> Simulation -> (Simulation, Cmd Action)
update action sim = case action of
Init sim -> (sim, Cmd.none)
Tick t -> simulate t sim
Plot p -> (startPlot p sim, Cmd.none)
--- DRAWING ---
stateColor : Exploration -> Color
stateColor state = case state of
Plotting _ -> yellow
Seeking _ -> green
Arriving _ -> red
Resting -> grey
drawSim : Simulation -> Html Action
drawSim sim = toHtml <| collage 600 600 <| drawGrid sim.grid
++ List.foldl (++) []
(List.indexedMap (\i e -> e |> drawVehicle (stateColor e.state)) sim.explorers)
++ case List.head sim.explorers of
Just e -> (circle 4 |> filled red |> move e.pos) :: case e.state of
Plotting goal -> drawTarget (solid red) (grid2screen goal sim.grid)
Seeking path -> [drawPath path sim.grid]
Arriving goal -> drawTarget (solid red) (grid2screen goal sim.grid)
Resting -> []
Nothing -> []