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(open
) do QuestHelper
: Assert(nil, "not empty in preparesearch") end
283 for _
, n
in pairs(self
.nodes
) do
288 local function Graph_AddStartNode(self
, n
, g
, end_list
)
289 local open
= self
.open
300 local mn
, mx
= 1, #open
303 local m
= floor((mn
+mx
)*0.5)
304 if open
[m
].g
> og
then
311 while open
[mn
] ~= n
do
315 table.remove(open
, mn
)
317 return -- Don't want to insert the node a second time.
321 local mn
, mx
= 1, #open
+1
324 local m
= floor((mn
+mx
)*0.5)
326 if open
[m
].g
> g
then
333 table.insert(open
, mn
, n
)
338 local function Graph_DoSearch(self
, end_list
)
339 local open
= self
.open
340 local end_count
= #end_list
343 local current
= table.remove(open
)
345 if current
.s
== 3 or current
.s
== 4 then
354 for n
, d
in pairs(current
.n
) do
355 if n
.s
== 0 or n
.s
== 3 then
356 -- Haven't visited this node yet.
361 n
.s
= n
.s
== 3 and 4 or 1
363 local mn
, mx
= 1, #open
+1
366 local m
= floor((mn
+mx
)*0.5)
368 if open
[m
].g
> g
then
375 table.insert(open
, mn
, n
)
376 elseif n
.s
== 1 or n
.s
== 4 then
382 local mn
, mx
= 1, #open
385 local m
= floor((mn
+mx
)*0.5)
386 if open
[m
].g
> og
then
393 while open
[mn
] ~= n
do
399 table.remove(open
, mn
)
402 local m
= floor((mn
+mx
)*0.5)
404 if open
[m
].g
> g
then
412 table.insert(open
, mn
, n
)
421 local function Graph_DoFullSearch(self
, end_list
)
422 local open
= self
.open
423 local end_count
= #end_list
426 local current
= table.remove(open
)
428 if current
.s
== 3 or current
.s
== 4 then
429 if end_count
== 1 then
430 for i
= 1,#removed
do
431 table.insert(end_list
, table.remove(removed
))
436 for i
= 1,end_count
do
437 if end_list
[i
] == current
then
438 table.insert(removed
, table.remove(end_list
, i
))
443 end_count
= end_count
- 1
450 for n
, d
in pairs(current
.n
) do
451 if n
.s
== 0 or n
.s
== 3 then
452 -- Haven't visited this node yet.
457 n
.s
= n
.s
== 3 and 4 or 1
459 local mn
, mx
= 1, #open
+1
462 local m
= floor((mn
+mx
)*0.5)
464 if open
[m
].g
> g
then
471 table.insert(open
, mn
, n
)
472 elseif n
.s
== 1 or n
.s
== 4 then
478 local mn
, mx
= 1, #open
481 local m
= floor((mn
+mx
)*0.5)
482 if open
[m
].g
> og
then
489 while open
[mn
] ~= n
do
495 table.remove(open
, mn
)
498 local m
= floor((mn
+mx
)*0.5)
500 if open
[m
].g
> g
then
508 table.insert(open
, mn
, n
)
514 for i
, n
in ipairs(end_list
) do
515 QuestHelper
:TextOut(i
..") Failed to reach: "..n
.name
..", s="..n
.s
)
518 for i
= 1,#removed
do
519 table.insert(end_list
, table.remove(removed
))
522 for i
, n
in ipairs(end_list
) do
523 QuestHelper
:TextOut(i
..") End node: "..n
.name
..", s="..n
.s
)
526 QuestHelper
:Error("Boom!")
528 for i
= 1,#removed
do
529 table.insert(end_list
, table.remove(removed
))
533 local function propLinks(node
)
536 for n
in pairs(node
.n
) do
542 function Graph_SanityCheck(self
)
543 for i
= 1,#self
.nodes
do
544 for _
, n
in ipairs(self
.nodes
) do
548 propLinks(self
.nodes
[i
])
550 for _
, n
in ipairs(self
.nodes
) do
552 QuestHelper
:TextOut((n
.name
or "unknown").." isn't reachable from "..(self
.nodes
[i
].name
or "unknown"))
558 function QuestHelper
:CreateGraph()
559 local graph
= self
:CreateTable("graph")
560 graph
.nodes
= self
:CreateTable("graph.nodes")
561 graph
.end_nodes
= self
:CreateTable("graph.end_nodes")
562 graph
.open
= self
:CreateTable("graph.open")
564 graph
.CreateNode
= Graph_CreateNode
565 graph
.DestroyNode
= Graph_DestroyNode
566 graph
.Reset
= Graph_Reset
568 graph
.PrepareSearch
= Graph_PrepareSearch
570 graph
.AddRouteStartNode
= Graph_AddRouteStartNode
571 graph
.DoRouteSearch
= Graph_DoRouteSearch
572 graph
.Search
= Graph_Search
573 graph
.SanityCheck
= Graph_SanityCheck
575 -- These don't deal with finding paths and instead only care about finding distances.
576 graph
.AddStartNode
= Graph_AddStartNode
577 graph
.DoSearch
= Graph_DoSearch
578 graph
.DoFullSearch
= Graph_DoFullSearch
583 function QuestHelper
:ReleaseGraph(graph
)
585 self
:ReleaseTable(graph
.nodes
)
586 self
:ReleaseTable(graph
.end_nodes
)
587 self
:ReleaseTable(graph
.open
)
588 self
:ReleaseTable(graph
)
591 QuestHelper
.world_graph
= QuestHelper
:CreateGraph()