1 -- Functions we use here.
2 local create
= QuestHelper
.create
3 local createSortedList
= QuestHelper
.createSortedList
4 local release
= QuestHelper
.release
5 local insert
= table.insert
6 local erase
= table.remove
8 -- The metatables for Graph and Node objects.
9 local Graph
, Node
= {}, {}
11 function Node
:onCreate()
12 rawset(self
, "_link", create())
15 function Node
:onRelease()
16 release(rawget(self
, "_link"))
19 -- Links this node to another.
20 function Node
:link(node
, dist
)
21 rawset(rawget(self
, "_link"), node
, dist
)
24 local function nodeCmpA(a
, b
)
25 -- In A*f is the traveled distance plus the estimated remaining distance.
26 return rawget(a
, "_f") > rawget(b
, "_f")
29 local function nodeCmpD(a
, b
)
30 -- In Dijkstra is the distance traveled so far.
31 return rawget(a
, "g") > rawget(b
, "g")
34 function Graph
:onCreate(heuristic
)
35 rawset(self
, "heuristic", heuristic
)
36 rawset(self
, "open", createSortedList(heuristic
and nodeCmpA
or nodeCmpD
))
37 rawset(self
, "nodes", create())
40 function Graph
:onRelease()
41 release(rawget(self
, "open"))
42 local nodes
= rawget(self
, "nodes")
43 for node
in pairs(nodes
) do release(node
) end
47 function Graph
:createNode()
48 local node
= create(Node
)
49 rawget(self
, "nodes")[node
] = true
53 function Graph
:releaseNode(node
)
55 rawget(self
, "nodes")[node
] = nil
58 -- Prepares the graph for searching.
59 function Graph
:clear()
60 local open
= rawget(self
, "open")
61 while erase(open
) do end
63 for n
in pairs(rawget(self
, "nodes")) do
64 -- Remove state from node.
65 -- Possible values for s:
66 -- nil/false - Hasn't yet been considered.
67 -- 1 - It's been placed in the open table.
68 -- other - We know how to reach this node.
73 -- The same node must not be added multiple times.
74 function Graph
:start(node
, dist
)
75 assert(not rawget(node
, "_s")) -- Should only be added once.
76 rawset(node
, "g", dist
or 0)
78 if rawget(self
, "heuristic") then
79 -- Just append the node to the end of the list, it will be sorted when
80 -- we have a node with which to apply the heuristic.
81 insert(rawget(self
, "open"), node
)
83 -- Insert in the correct position now; with no heuristic to change things
84 -- the list won't need to be resorted later.
85 rawget(self
, "open"):insert(node
)
89 function Graph
:dest(dest
)
90 local open
= rawget(self
, "open")
92 if rawget(dest
, "_s") == 2 then
93 -- We've already reached this node.
97 local heuristic
= rawget(self
, "heuristic")
103 local n
= rawget(open
, i
)
104 local g
, h
= rawget(n
, "g"), heuristic(n
, dest
)
112 local node
= erase(open
)
113 rawset(node
, "_s", 2)
115 local g
= rawget(node
, "g")
117 for n
, d
in pairs(rawget(node
, "_link")) do
118 local s
= rawget(n
, "_s")
120 -- Is already in the open list, possibly we found a shorter route to it.
122 local h
= rawget(n
, "_h")
124 if f
< rawget(n
, "_f") then
125 -- Found a shorter path to this node.
126 local i
= open
:lower(n
)
127 while rawget(open
, i
) ~= n
do i
= i
+ 1 end
131 rawset(n
, "parent", node
)
132 open
:insert2(n
, i
, #open
+1)
135 -- Haven't considered this node yet.
136 local h
= heuristic(n
, dest
)
139 rawset(n
, "_f", ng
+h
)
142 rawset(n
, "parent", node
)
144 end -- else the node in question is ignored.
148 -- We could have checked for this before the above loop, but then we'd have missed some links
149 -- if this was to be called multiple times.
154 -- Dijkstra's algorithm
155 -- Same as above, but we don't need to resort the list (already sorted), and only consider the distance traveled.
158 local node
= erase(open
)
159 rawset(node
, "_s", 2)
161 local g
= rawget(node
, "g")
163 for n
, d
in pairs(rawget(node
, "_link")) do
164 local s
= rawget(n
, "_s")
166 -- Is already in the open list, possibly we found a shorter route to it.
168 if ng
< rawget(n
, "g") then
169 -- Found a shorter path to this node.
170 local i
= open
:lower(n
)
171 while rawget(open
, i
) ~= n
do i
= i
+ 1 end
174 rawset(n
, "parent", node
)
175 open
:insert2(n
, i
, #open
+1)
178 -- Haven't considered this node yet.
181 rawset(n
, "parent", node
)
183 end -- else the node in question is ignored.
187 -- We could have checked for this before the above loop, but then we'd have missed some links
188 -- if this was to be called multiple times.
195 Graph
.__newindex
= function()
196 assert(false, "Shouldn't assign values.")
199 Node
.__index
= function(node
, key
)
200 return rawget(node
, key
) or rawget(Node
, key
)
203 Graph
.__index
= function(_
, key
)
204 return rawget(Graph
, key
)
207 local function createGraph(heuristic
)
208 return create(Graph
, heuristic
)
211 QuestHelper
.createGraph
= createGraph