1 QuestHelper_File
["graph.lua"] = "Development Version"
3 local floor = math
.floor
5 local function Graph_Search(self
, first
, last
)
8 while #open
> 0 do table.remove(open
) end
9 for _
, n
in ipairs(self
.nodes
) do n
.s
= 0 end
11 table.insert(open
, first
)
17 local current
= table.remove(open
)
19 if current
== last
then
27 for n
, d
in pairs(current
.n
) do
29 -- Haven't visited this node yet.
35 local mn
, mx
= 1, #open
+1
38 local m
= floor((mn
+mx
)*0.5)
47 table.insert(open
, mn
, n
)
53 local mn
, mx
= 1, #open
56 local m
= floor((mn
+mx
)*0.5)
64 while open
[mn
] ~= n
do
68 table.remove(open
, mn
)
71 local m
= floor((mn
+mx
)*0.5)
80 table.insert(open
, mn
, n
)
90 local function sanity(list
, node
)
92 local contains
= false
93 for i
, n
in ipairs(list
) do
94 if not (not last
or last
>= n
.g
) then
95 for i
, n
in ipairs(list
) do
96 QuestHelper
:TextOut(i
..") "..n
.g
)
98 QuestHelper
:Error("Order "..i
.."/"..#list
.." ("..n
.g
..")")
100 assert(not last
or last
>= n
.g
)
106 if node
and not contains
then QuestHelper
:Error("Missing") end
109 local function Graph_Node_Link(self
, next_node
, distance
)
110 if type(distance
) ~= "number" or distance
< 0 then QuestHelper
:Error("Boom!") end
111 if self
~= next_node
then
112 self
.n
[next_node
] = distance
113 table.insert(next_node
.r
, self
)
117 local function Graph_CreateNode(self
)
118 local node
= QuestHelper
:CreateTable("graph_createnode")
119 node
.Link
= Graph_Node_Link
120 node
.n
= QuestHelper
:CreateTable("graph_createnode.n")
121 node
.r
= QuestHelper
:CreateTable("graph_createnode.r")
122 table.insert(self
.nodes
, node
)
126 local function Graph_DestroyNode(self
, node
)
127 for i
= 1,#self
.nodes
do
128 if self
.nodes
[i
] == node
then
129 table.remove(self
.nodes
, i
)
130 QuestHelper
:ReleaseTable(node
.n
)
131 QuestHelper
:ReleaseTable(node
.r
)
132 QuestHelper
:ReleaseTable(node
)
138 local function Graph_Reset(self
)
139 while #self
.nodes
> 0 do
140 local node
= table.remove(self
.nodes
)
141 QuestHelper
:ReleaseTable(node
.n
)
142 QuestHelper
:ReleaseTable(node
.r
)
143 QuestHelper
:ReleaseTable(node
)
147 local function Graph_AddRouteStartNode(self
, n
, g
, end_list
)
148 local open
= self
.open
159 local mn
, mx
= 1, #open
162 local m
= floor((mn
+mx
)*0.5)
163 if open
[m
].g
> og
then
170 while open
[mn
] ~= n
do
174 table.remove(open
, mn
)
176 return -- Don't want to insert the node a second time.
180 local mn
, mx
= 1, #open
+1
183 local m
= floor((mn
+mx
)*0.5)
185 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
))
186 if open
[m
].g
> g
then
193 table.insert(open
, mn
, n
)
198 local function Graph_DoRouteSearch(self
, end_list
)
199 local open
= self
.open
200 local end_count
= #end_list
203 local current
= table.remove(open
)
205 if current
.s
== 3 or current
.s
== 4 then
214 for n
, d
in pairs(current
.n
) do
215 if n
.s
== 0 or n
.s
== 3 then
216 -- Haven't visited this node yet.
221 n
.s
= n
.s
== 3 and 4 or 1
223 local mn
, mx
= 1, #open
+1
226 local m
= floor((mn
+mx
)*0.5)
228 if open
[m
].g
> g
then
235 table.insert(open
, mn
, n
)
236 elseif n
.s
== 1 or n
.s
== 4 then
242 local mn
, mx
= 1, #open
245 local m
= floor((mn
+mx
)*0.5)
246 if open
[m
].g
> og
then
253 while open
[mn
] ~= n
do
259 table.remove(open
, mn
)
262 local m
= floor((mn
+mx
)*0.5)
264 if open
[m
].g
> g
then
272 table.insert(open
, mn
, n
)
279 local function Graph_PrepareSearch(self
)
280 local open
= self
.open
281 for n
in pairs(open
) do open
[n
] = nil end
282 for _
, n
in pairs(self
.nodes
) do
287 local function Graph_AddStartNode(self
, n
, g
, end_list
)
288 local open
= self
.open
299 local mn
, mx
= 1, #open
302 local m
= floor((mn
+mx
)*0.5)
303 if open
[m
].g
> og
then
310 while open
[mn
] ~= n
do
314 table.remove(open
, mn
)
316 return -- Don't want to insert the node a second time.
320 local mn
, mx
= 1, #open
+1
323 local m
= floor((mn
+mx
)*0.5)
325 if open
[m
].g
> g
then
332 table.insert(open
, mn
, n
)
337 local function Graph_DoSearch(self
, end_list
)
338 local open
= self
.open
339 local end_count
= #end_list
342 local current
= table.remove(open
)
344 if current
.s
== 3 or current
.s
== 4 then
353 for n
, d
in pairs(current
.n
) do
354 if n
.s
== 0 or n
.s
== 3 then
355 -- Haven't visited this node yet.
360 n
.s
= n
.s
== 3 and 4 or 1
362 local mn
, mx
= 1, #open
+1
365 local m
= floor((mn
+mx
)*0.5)
367 if open
[m
].g
> g
then
374 table.insert(open
, mn
, n
)
375 elseif n
.s
== 1 or n
.s
== 4 then
381 local mn
, mx
= 1, #open
384 local m
= floor((mn
+mx
)*0.5)
385 if open
[m
].g
> og
then
392 while open
[mn
] ~= n
do
398 table.remove(open
, mn
)
401 local m
= floor((mn
+mx
)*0.5)
403 if open
[m
].g
> g
then
411 table.insert(open
, mn
, n
)
420 local function Graph_DoFullSearch(self
, end_list
)
421 local open
= self
.open
422 local end_count
= #end_list
425 local current
= table.remove(open
)
427 if current
.s
== 3 or current
.s
== 4 then
428 if end_count
== 1 then
429 for i
= 1,#removed
do
430 table.insert(end_list
, table.remove(removed
))
435 for i
= 1,end_count
do
436 if end_list
[i
] == current
then
437 table.insert(removed
, table.remove(end_list
, i
))
442 end_count
= end_count
- 1
449 for n
, d
in pairs(current
.n
) do
450 if n
.s
== 0 or n
.s
== 3 then
451 -- Haven't visited this node yet.
456 n
.s
= n
.s
== 3 and 4 or 1
458 local mn
, mx
= 1, #open
+1
461 local m
= floor((mn
+mx
)*0.5)
463 if open
[m
].g
> g
then
470 table.insert(open
, mn
, n
)
471 elseif n
.s
== 1 or n
.s
== 4 then
477 local mn
, mx
= 1, #open
480 local m
= floor((mn
+mx
)*0.5)
481 if open
[m
].g
> og
then
488 while open
[mn
] ~= n
do
494 table.remove(open
, mn
)
497 local m
= floor((mn
+mx
)*0.5)
499 if open
[m
].g
> g
then
507 table.insert(open
, mn
, n
)
513 for i
, n
in ipairs(end_list
) do
514 QuestHelper
:TextOut(i
..") Failed to reach: "..n
.name
..", s="..n
.s
)
517 for i
= 1,#removed
do
518 table.insert(end_list
, table.remove(removed
))
521 for i
, n
in ipairs(end_list
) do
522 QuestHelper
:TextOut(i
..") End node: "..n
.name
..", s="..n
.s
)
525 QuestHelper
:Error("Boom!")
527 for i
= 1,#removed
do
528 table.insert(end_list
, table.remove(removed
))
532 local function propLinks(node
)
535 for n
in pairs(node
.n
) do
541 function Graph_SanityCheck(self
)
542 for i
= 1,#self
.nodes
do
543 for _
, n
in ipairs(self
.nodes
) do
547 propLinks(self
.nodes
[i
])
549 for _
, n
in ipairs(self
.nodes
) do
551 QuestHelper
:TextOut((n
.name
or "unknown").." isn't reachable from "..(self
.nodes
[i
].name
or "unknown"))
557 function QuestHelper
:CreateGraph()
558 local graph
= self
:CreateTable("graph")
559 graph
.nodes
= self
:CreateTable("graph.nodes")
560 graph
.end_nodes
= self
:CreateTable("graph.end_nodes")
561 graph
.open
= self
:CreateTable("graph.open")
563 graph
.CreateNode
= Graph_CreateNode
564 graph
.DestroyNode
= Graph_DestroyNode
565 graph
.Reset
= Graph_Reset
567 graph
.PrepareSearch
= Graph_PrepareSearch
569 graph
.AddRouteStartNode
= Graph_AddRouteStartNode
570 graph
.DoRouteSearch
= Graph_DoRouteSearch
571 graph
.Search
= Graph_Search
572 graph
.SanityCheck
= Graph_SanityCheck
574 -- These don't deal with finding paths and instead only care about finding distances.
575 graph
.AddStartNode
= Graph_AddStartNode
576 graph
.DoSearch
= Graph_DoSearch
577 graph
.DoFullSearch
= Graph_DoFullSearch
582 function QuestHelper
:ReleaseGraph(graph
)
584 self
:ReleaseTable(graph
.nodes
)
585 self
:ReleaseTable(graph
.end_nodes
)
586 self
:ReleaseTable(graph
.open
)
587 self
:ReleaseTable(graph
)
590 QuestHelper
.world_graph
= QuestHelper
:CreateGraph()