1 QuestHelper_File
["graph.lua"] = "Development Version"
2 QuestHelper_Loadtime
["graph.lua"] = GetTime()
4 do return end -- guhhhh
6 local floor = math
.floor
8 local function Graph_Search(self
, first
, last
)
10 local open
= self
.open
11 while #open
> 0 do table.remove(open
) end
12 for _
, n
in ipairs(self
.nodes
) do n
.s
= 0 end
14 table.insert(open
, first
)
20 local current
= table.remove(open
)
22 if current
== last
then
30 for n
, d
in pairs(current
.n
) do
32 -- Haven't visited this node yet.
38 local mn
, mx
= 1, #open
+1
41 local m
= floor((mn
+mx
)*0.5)
50 table.insert(open
, mn
, n
)
56 local mn
, mx
= 1, #open
59 local m
= floor((mn
+mx
)*0.5)
67 while open
[mn
] ~= n
do
71 table.remove(open
, mn
)
74 local m
= floor((mn
+mx
)*0.5)
83 table.insert(open
, mn
, n
)
93 local function sanity(list
, node
)
95 local contains
= false
96 for i
, n
in ipairs(list
) do
97 if not (not last
or last
>= n
.g
) then
98 for i
, n
in ipairs(list
) do
99 QuestHelper
:TextOut(i
..") "..n
.g
)
101 QuestHelper
:Error("Order "..i
.."/"..#list
.." ("..n
.g
..")")
103 assert(not last
or last
>= n
.g
)
109 if node
and not contains
then QuestHelper
:Error("Missing") end
112 local function Graph_Node_Link(self
, next_node
, distance
)
113 if type(distance
) ~= "number" or distance
< 0 then QuestHelper
:Error("Boom!") end
114 if self
~= next_node
then
115 self
.n
[next_node
] = distance
116 table.insert(next_node
.r
, self
)
120 local function Graph_CreateNode(self
)
121 local node
= QuestHelper
:CreateTable("graph_createnode")
122 node
.Link
= Graph_Node_Link
123 node
.n
= QuestHelper
:CreateTable("graph_createnode.n")
124 node
.r
= QuestHelper
:CreateTable("graph_createnode.r")
125 table.insert(self
.nodes
, node
)
129 local function Graph_DestroyNode(self
, node
)
130 for i
= 1,#self
.nodes
do
131 if self
.nodes
[i
] == node
then
132 table.remove(self
.nodes
, i
)
133 QuestHelper
:ReleaseTable(node
.n
)
134 QuestHelper
:ReleaseTable(node
.r
)
135 QuestHelper
:ReleaseTable(node
)
141 local function Graph_Reset(self
)
142 while #self
.nodes
> 0 do
143 local node
= table.remove(self
.nodes
)
144 QuestHelper
:ReleaseTable(node
.n
)
145 QuestHelper
:ReleaseTable(node
.r
)
146 QuestHelper
:ReleaseTable(node
)
150 local function Graph_AddRouteStartNode(self
, n
, g
, end_list
)
151 local open
= self
.open
162 local mn
, mx
= 1, #open
165 local m
= floor((mn
+mx
)*0.5)
166 if open
[m
].g
> og
then
173 while open
[mn
] ~= n
do
177 table.remove(open
, mn
)
179 return -- Don't want to insert the node a second time.
183 local mn
, mx
= 1, #open
+1
186 local m
= floor((mn
+mx
)*0.5)
188 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
))
189 if open
[m
].g
> g
then
196 table.insert(open
, mn
, n
)
201 local function Graph_DoRouteSearch(self
, end_list
)
202 local open
= self
.open
203 local end_count
= #end_list
206 local current
= table.remove(open
)
208 if current
.s
== 3 or current
.s
== 4 then
217 for n
, d
in pairs(current
.n
) do
218 if n
.s
== 0 or n
.s
== 3 then
219 -- Haven't visited this node yet.
224 n
.s
= n
.s
== 3 and 4 or 1
226 local mn
, mx
= 1, #open
+1
229 local m
= floor((mn
+mx
)*0.5)
231 if open
[m
].g
> g
then
238 table.insert(open
, mn
, n
)
239 elseif n
.s
== 1 or n
.s
== 4 then
245 local mn
, mx
= 1, #open
248 local m
= floor((mn
+mx
)*0.5)
249 if open
[m
].g
> og
then
256 while open
[mn
] ~= n
do
262 table.remove(open
, mn
)
265 local m
= floor((mn
+mx
)*0.5)
267 if open
[m
].g
> g
then
275 table.insert(open
, mn
, n
)
282 local function Graph_PrepareSearch(self
)
283 local open
= self
.open
284 for n
in pairs(open
) do open
[n
] = nil end
285 for n
in pairs(open
) do QuestHelper
: Assert(nil, "not empty in preparesearch") end
286 for _
, n
in pairs(self
.nodes
) do
291 local function Graph_AddStartNode(self
, n
, g
, end_list
)
292 local open
= self
.open
303 local mn
, mx
= 1, #open
306 local m
= floor((mn
+mx
)*0.5)
307 if open
[m
].g
> og
then
314 while open
[mn
] ~= n
do
318 table.remove(open
, mn
)
320 return -- Don't want to insert the node a second time.
324 local mn
, mx
= 1, #open
+1
327 local m
= floor((mn
+mx
)*0.5)
329 if open
[m
].g
> g
then
336 table.insert(open
, mn
, n
)
341 local function Graph_DoSearch(self
, end_list
)
342 local open
= self
.open
343 local end_count
= #end_list
346 local current
= table.remove(open
)
348 if current
.s
== 3 or current
.s
== 4 then
357 for n
, d
in pairs(current
.n
) do
358 if n
.s
== 0 or n
.s
== 3 then
359 -- Haven't visited this node yet.
364 n
.s
= n
.s
== 3 and 4 or 1
366 local mn
, mx
= 1, #open
+1
369 local m
= floor((mn
+mx
)*0.5)
371 if open
[m
].g
> g
then
378 table.insert(open
, mn
, n
)
379 elseif n
.s
== 1 or n
.s
== 4 then
385 local mn
, mx
= 1, #open
388 local m
= floor((mn
+mx
)*0.5)
389 if open
[m
].g
> og
then
396 while open
[mn
] ~= n
do
402 table.remove(open
, mn
)
405 local m
= floor((mn
+mx
)*0.5)
407 if open
[m
].g
> g
then
415 table.insert(open
, mn
, n
)
424 local function Graph_DoFullSearch(self
, end_list
)
425 local open
= self
.open
426 local end_count
= #end_list
429 local current
= table.remove(open
)
431 if current
.s
== 3 or current
.s
== 4 then
432 if end_count
== 1 then
433 for i
= 1,#removed
do
434 table.insert(end_list
, table.remove(removed
))
439 for i
= 1,end_count
do
440 if end_list
[i
] == current
then
441 table.insert(removed
, table.remove(end_list
, i
))
446 end_count
= end_count
- 1
453 for n
, d
in pairs(current
.n
) do
454 if n
.s
== 0 or n
.s
== 3 then
455 -- Haven't visited this node yet.
460 n
.s
= n
.s
== 3 and 4 or 1
462 local mn
, mx
= 1, #open
+1
465 local m
= floor((mn
+mx
)*0.5)
467 if open
[m
].g
> g
then
474 table.insert(open
, mn
, n
)
475 elseif n
.s
== 1 or n
.s
== 4 then
481 local mn
, mx
= 1, #open
484 local m
= floor((mn
+mx
)*0.5)
485 if open
[m
].g
> og
then
492 while open
[mn
] ~= n
do
498 table.remove(open
, mn
)
501 local m
= floor((mn
+mx
)*0.5)
503 if open
[m
].g
> g
then
511 table.insert(open
, mn
, n
)
517 for i
, n
in ipairs(end_list
) do
518 QuestHelper
:TextOut(i
..") Failed to reach: "..n
.name
..", s="..n
.s
)
521 for i
= 1,#removed
do
522 table.insert(end_list
, table.remove(removed
))
525 for i
, n
in ipairs(end_list
) do
526 QuestHelper
:TextOut(i
..") End node: "..n
.name
..", s="..n
.s
)
529 QuestHelper
:Error("Boom!")
531 for i
= 1,#removed
do
532 table.insert(end_list
, table.remove(removed
))
536 local function propLinks(node
)
539 for n
in pairs(node
.n
) do
545 function Graph_SanityCheck(self
)
546 for i
= 1,#self
.nodes
do
547 for _
, n
in ipairs(self
.nodes
) do
551 propLinks(self
.nodes
[i
])
553 for _
, n
in ipairs(self
.nodes
) do
555 QuestHelper
:TextOut((n
.name
or "unknown").." isn't reachable from "..(self
.nodes
[i
].name
or "unknown"))
561 function QuestHelper
:CreateGraph()
562 local graph
= self
:CreateTable("graph")
563 graph
.nodes
= self
:CreateTable("graph.nodes")
564 graph
.end_nodes
= self
:CreateTable("graph.end_nodes")
565 graph
.open
= self
:CreateTable("graph.open")
567 graph
.CreateNode
= Graph_CreateNode
568 graph
.DestroyNode
= Graph_DestroyNode
569 graph
.Reset
= Graph_Reset
571 graph
.PrepareSearch
= Graph_PrepareSearch
573 graph
.AddRouteStartNode
= Graph_AddRouteStartNode
574 graph
.DoRouteSearch
= Graph_DoRouteSearch
575 graph
.Search
= Graph_Search
576 graph
.SanityCheck
= Graph_SanityCheck
578 -- These don't deal with finding paths and instead only care about finding distances.
579 graph
.AddStartNode
= Graph_AddStartNode
580 graph
.DoSearch
= Graph_DoSearch
581 graph
.DoFullSearch
= Graph_DoFullSearch
586 function QuestHelper
:ReleaseGraph(graph
)
588 self
:ReleaseTable(graph
.nodes
)
589 self
:ReleaseTable(graph
.end_nodes
)
590 self
:ReleaseTable(graph
.open
)
591 self
:ReleaseTable(graph
)
594 QuestHelper
.world_graph
= QuestHelper
:CreateGraph()