1 QuestHelper_File
["graph.lua"] = "Development Version"
2 QuestHelper_Loadtime
["graph.lua"] = GetTime()
4 local floor = math
.floor
6 local function Graph_Search(self
, first
, last
)
9 while #open
> 0 do table.remove(open
) end
10 for _
, n
in ipairs(self
.nodes
) do n
.s
= 0 end
12 table.insert(open
, first
)
18 local current
= table.remove(open
)
20 if current
== last
then
28 for n
, d
in pairs(current
.n
) do
30 -- Haven't visited this node yet.
36 local mn
, mx
= 1, #open
+1
39 local m
= floor((mn
+mx
)*0.5)
48 table.insert(open
, mn
, n
)
54 local mn
, mx
= 1, #open
57 local m
= floor((mn
+mx
)*0.5)
65 while open
[mn
] ~= n
do
69 table.remove(open
, mn
)
72 local m
= floor((mn
+mx
)*0.5)
81 table.insert(open
, mn
, n
)
91 local function sanity(list
, node
)
93 local contains
= false
94 for i
, n
in ipairs(list
) do
95 if not (not last
or last
>= n
.g
) then
96 for i
, n
in ipairs(list
) do
97 QuestHelper
:TextOut(i
..") "..n
.g
)
99 QuestHelper
:Error("Order "..i
.."/"..#list
.." ("..n
.g
..")")
101 assert(not last
or last
>= n
.g
)
107 if node
and not contains
then QuestHelper
:Error("Missing") end
110 local function Graph_Node_Link(self
, next_node
, distance
)
111 if type(distance
) ~= "number" or distance
< 0 then QuestHelper
:Error("Boom!") end
112 if self
~= next_node
then
113 self
.n
[next_node
] = distance
114 table.insert(next_node
.r
, self
)
118 local function Graph_CreateNode(self
)
119 local node
= QuestHelper
:CreateTable("graph_createnode")
120 node
.Link
= Graph_Node_Link
121 node
.n
= QuestHelper
:CreateTable("graph_createnode.n")
122 node
.r
= QuestHelper
:CreateTable("graph_createnode.r")
123 table.insert(self
.nodes
, node
)
127 local function Graph_DestroyNode(self
, node
)
128 for i
= 1,#self
.nodes
do
129 if self
.nodes
[i
] == node
then
130 table.remove(self
.nodes
, i
)
131 QuestHelper
:ReleaseTable(node
.n
)
132 QuestHelper
:ReleaseTable(node
.r
)
133 QuestHelper
:ReleaseTable(node
)
139 local function Graph_Reset(self
)
140 while #self
.nodes
> 0 do
141 local node
= table.remove(self
.nodes
)
142 QuestHelper
:ReleaseTable(node
.n
)
143 QuestHelper
:ReleaseTable(node
.r
)
144 QuestHelper
:ReleaseTable(node
)
148 local function Graph_AddRouteStartNode(self
, n
, g
, end_list
)
149 local open
= self
.open
160 local mn
, mx
= 1, #open
163 local m
= floor((mn
+mx
)*0.5)
164 if open
[m
].g
> og
then
171 while open
[mn
] ~= n
do
175 table.remove(open
, mn
)
177 return -- Don't want to insert the node a second time.
181 local mn
, mx
= 1, #open
+1
184 local m
= floor((mn
+mx
)*0.5)
186 QuestHelper
: Assert(open
[m
].g
and g
, string.format("nil-with-number issue, %s %s and %d inside %d %d", tostring(open
[m
].g
), tostring(g
), m
, mn
, mx
))
187 if open
[m
].g
> g
then
194 table.insert(open
, mn
, n
)
199 local function Graph_DoRouteSearch(self
, end_list
)
200 local open
= self
.open
201 local end_count
= #end_list
204 local current
= table.remove(open
)
206 if current
.s
== 3 or current
.s
== 4 then
215 for n
, d
in pairs(current
.n
) do
216 if n
.s
== 0 or n
.s
== 3 then
217 -- Haven't visited this node yet.
222 n
.s
= n
.s
== 3 and 4 or 1
224 local mn
, mx
= 1, #open
+1
227 local m
= floor((mn
+mx
)*0.5)
229 if open
[m
].g
> g
then
236 table.insert(open
, mn
, n
)
237 elseif n
.s
== 1 or n
.s
== 4 then
243 local mn
, mx
= 1, #open
246 local m
= floor((mn
+mx
)*0.5)
247 if open
[m
].g
> og
then
254 while open
[mn
] ~= n
do
260 table.remove(open
, mn
)
263 local m
= floor((mn
+mx
)*0.5)
265 if open
[m
].g
> g
then
273 table.insert(open
, mn
, n
)
280 local function Graph_PrepareSearch(self
)
281 local open
= self
.open
282 for n
in pairs(open
) do open
[n
] = nil end
283 for n
in pairs(open
) do QuestHelper
: Assert(nil, "not empty in preparesearch") end
284 for _
, n
in pairs(self
.nodes
) do
289 local function Graph_AddStartNode(self
, n
, g
, end_list
)
290 local open
= self
.open
301 local mn
, mx
= 1, #open
304 local m
= floor((mn
+mx
)*0.5)
305 if open
[m
].g
> og
then
312 while open
[mn
] ~= n
do
316 table.remove(open
, mn
)
318 return -- Don't want to insert the node a second time.
322 local mn
, mx
= 1, #open
+1
325 local m
= floor((mn
+mx
)*0.5)
327 if open
[m
].g
> g
then
334 table.insert(open
, mn
, n
)
339 local function Graph_DoSearch(self
, end_list
)
340 local open
= self
.open
341 local end_count
= #end_list
344 local current
= table.remove(open
)
346 if current
.s
== 3 or current
.s
== 4 then
355 for n
, d
in pairs(current
.n
) do
356 if n
.s
== 0 or n
.s
== 3 then
357 -- Haven't visited this node yet.
362 n
.s
= n
.s
== 3 and 4 or 1
364 local mn
, mx
= 1, #open
+1
367 local m
= floor((mn
+mx
)*0.5)
369 if open
[m
].g
> g
then
376 table.insert(open
, mn
, n
)
377 elseif n
.s
== 1 or n
.s
== 4 then
383 local mn
, mx
= 1, #open
386 local m
= floor((mn
+mx
)*0.5)
387 if open
[m
].g
> og
then
394 while open
[mn
] ~= n
do
400 table.remove(open
, mn
)
403 local m
= floor((mn
+mx
)*0.5)
405 if open
[m
].g
> g
then
413 table.insert(open
, mn
, n
)
422 local function Graph_DoFullSearch(self
, end_list
)
423 local open
= self
.open
424 local end_count
= #end_list
427 local current
= table.remove(open
)
429 if current
.s
== 3 or current
.s
== 4 then
430 if end_count
== 1 then
431 for i
= 1,#removed
do
432 table.insert(end_list
, table.remove(removed
))
437 for i
= 1,end_count
do
438 if end_list
[i
] == current
then
439 table.insert(removed
, table.remove(end_list
, i
))
444 end_count
= end_count
- 1
451 for n
, d
in pairs(current
.n
) do
452 if n
.s
== 0 or n
.s
== 3 then
453 -- Haven't visited this node yet.
458 n
.s
= n
.s
== 3 and 4 or 1
460 local mn
, mx
= 1, #open
+1
463 local m
= floor((mn
+mx
)*0.5)
465 if open
[m
].g
> g
then
472 table.insert(open
, mn
, n
)
473 elseif n
.s
== 1 or n
.s
== 4 then
479 local mn
, mx
= 1, #open
482 local m
= floor((mn
+mx
)*0.5)
483 if open
[m
].g
> og
then
490 while open
[mn
] ~= n
do
496 table.remove(open
, mn
)
499 local m
= floor((mn
+mx
)*0.5)
501 if open
[m
].g
> g
then
509 table.insert(open
, mn
, n
)
515 for i
, n
in ipairs(end_list
) do
516 QuestHelper
:TextOut(i
..") Failed to reach: "..n
.name
..", s="..n
.s
)
519 for i
= 1,#removed
do
520 table.insert(end_list
, table.remove(removed
))
523 for i
, n
in ipairs(end_list
) do
524 QuestHelper
:TextOut(i
..") End node: "..n
.name
..", s="..n
.s
)
527 QuestHelper
:Error("Boom!")
529 for i
= 1,#removed
do
530 table.insert(end_list
, table.remove(removed
))
534 local function propLinks(node
)
537 for n
in pairs(node
.n
) do
543 function Graph_SanityCheck(self
)
544 for i
= 1,#self
.nodes
do
545 for _
, n
in ipairs(self
.nodes
) do
549 propLinks(self
.nodes
[i
])
551 for _
, n
in ipairs(self
.nodes
) do
553 QuestHelper
:TextOut((n
.name
or "unknown").." isn't reachable from "..(self
.nodes
[i
].name
or "unknown"))
559 function QuestHelper
:CreateGraph()
560 local graph
= self
:CreateTable("graph")
561 graph
.nodes
= self
:CreateTable("graph.nodes")
562 graph
.end_nodes
= self
:CreateTable("graph.end_nodes")
563 graph
.open
= self
:CreateTable("graph.open")
565 graph
.CreateNode
= Graph_CreateNode
566 graph
.DestroyNode
= Graph_DestroyNode
567 graph
.Reset
= Graph_Reset
569 graph
.PrepareSearch
= Graph_PrepareSearch
571 graph
.AddRouteStartNode
= Graph_AddRouteStartNode
572 graph
.DoRouteSearch
= Graph_DoRouteSearch
573 graph
.Search
= Graph_Search
574 graph
.SanityCheck
= Graph_SanityCheck
576 -- These don't deal with finding paths and instead only care about finding distances.
577 graph
.AddStartNode
= Graph_AddStartNode
578 graph
.DoSearch
= Graph_DoSearch
579 graph
.DoFullSearch
= Graph_DoFullSearch
584 function QuestHelper
:ReleaseGraph(graph
)
586 self
:ReleaseTable(graph
.nodes
)
587 self
:ReleaseTable(graph
.end_nodes
)
588 self
:ReleaseTable(graph
.open
)
589 self
:ReleaseTable(graph
)
592 QuestHelper
.world_graph
= QuestHelper
:CreateGraph()