1 local floor = math
.floor
3 local function Graph_Search(self
, first
, last
)
6 while #open
> 0 do table.remove(open
) end
7 for _
, n
in ipairs(self
.nodes
) do n
.s
= 0 end
9 table.insert(open
, first
)
15 local current
= table.remove(open
)
17 if current
== last
then
25 for n
, d
in pairs(current
.n
) do
27 -- Haven't visited this node yet.
33 local mn
, mx
= 1, #open
+1
36 local m
= floor((mn
+mx
)*0.5)
45 table.insert(open
, mn
, n
)
51 local mn
, mx
= 1, #open
54 local m
= floor((mn
+mx
)*0.5)
62 while open
[mn
] ~= n
do
66 table.remove(open
, mn
)
69 local m
= floor((mn
+mx
)*0.5)
78 table.insert(open
, mn
, n
)
88 local function sanity(list
, node
)
90 local contains
= false
91 for i
, n
in ipairs(list
) do
92 if not (not last
or last
>= n
.g
) then
93 for i
, n
in ipairs(list
) do
94 QuestHelper
:TextOut(i
..") "..n
.g
)
96 QuestHelper
:Error("Order "..i
.."/"..#list
.." ("..n
.g
..")")
98 assert(not last
or last
>= n
.g
)
104 if node
and not contains
then QuestHelper
:Error("Missing") end
107 local function Graph_Node_Link(self
, next_node
, distance
)
108 if type(distance
) ~= "number" or distance
< 0 then QuestHelper
:Error("Boom!") end
109 if self
~= next_node
then
110 self
.n
[next_node
] = distance
111 table.insert(next_node
.r
, self
)
115 local function Graph_CreateNode(self
)
116 local node
= QuestHelper
:CreateTable()
117 node
.Link
= Graph_Node_Link
118 node
.n
= QuestHelper
:CreateTable()
119 node
.r
= QuestHelper
:CreateTable()
120 table.insert(self
.nodes
, node
)
124 local function Graph_DestroyNode(self
, node
)
125 for i
= 1,#self
.nodes
do
126 if self
.nodes
[i
] == node
then
127 table.remove(self
.nodes
, i
)
128 QuestHelper
:ReleaseTable(node
.n
)
129 QuestHelper
:ReleaseTable(node
.r
)
130 QuestHelper
:ReleaseTable(node
)
136 local function Graph_Reset(self
)
137 while #self
.nodes
> 0 do
138 local node
= table.remove(self
.nodes
)
139 QuestHelper
:ReleaseTable(node
.n
)
140 QuestHelper
:ReleaseTable(node
.r
)
141 QuestHelper
:ReleaseTable(node
)
145 local function Graph_AddRouteStartNode(self
, n
, g
, end_list
)
146 local open
= self
.open
157 local mn
, mx
= 1, #open
160 local m
= floor((mn
+mx
)*0.5)
161 if open
[m
].g
> og
then
168 while open
[mn
] ~= n
do
172 table.remove(open
, mn
)
174 return -- Don't want to insert the node a second time.
178 local mn
, mx
= 1, #open
+1
181 local m
= floor((mn
+mx
)*0.5)
183 if open
[m
].g
> g
then
190 table.insert(open
, mn
, n
)
195 local function Graph_DoRouteSearch(self
, end_list
)
196 local open
= self
.open
197 local end_count
= #end_list
200 local current
= table.remove(open
)
202 if current
.s
== 3 or current
.s
== 4 then
211 for n
, d
in pairs(current
.n
) do
212 if n
.s
== 0 or n
.s
== 3 then
213 -- Haven't visited this node yet.
218 n
.s
= n
.s
== 3 and 4 or 1
220 local mn
, mx
= 1, #open
+1
223 local m
= floor((mn
+mx
)*0.5)
225 if open
[m
].g
> g
then
232 table.insert(open
, mn
, n
)
233 elseif n
.s
== 1 or n
.s
== 4 then
239 local mn
, mx
= 1, #open
242 local m
= floor((mn
+mx
)*0.5)
243 if open
[m
].g
> og
then
250 while open
[mn
] ~= n
do
256 table.remove(open
, mn
)
259 local m
= floor((mn
+mx
)*0.5)
261 if open
[m
].g
> g
then
269 table.insert(open
, mn
, n
)
276 local function Graph_PrepareSearch(self
)
277 local open
= self
.open
278 for n
in pairs(open
) do open
[n
] = nil end
279 for _
, n
in pairs(self
.nodes
) do
284 local function Graph_AddStartNode(self
, n
, g
, end_list
)
285 local open
= self
.open
296 local mn
, mx
= 1, #open
299 local m
= floor((mn
+mx
)*0.5)
300 if open
[m
].g
> og
then
307 while open
[mn
] ~= n
do
311 table.remove(open
, mn
)
313 return -- Don't want to insert the node a second time.
317 local mn
, mx
= 1, #open
+1
320 local m
= floor((mn
+mx
)*0.5)
322 if open
[m
].g
> g
then
329 table.insert(open
, mn
, n
)
334 local function Graph_DoSearch(self
, end_list
)
335 local open
= self
.open
336 local end_count
= #end_list
339 local current
= table.remove(open
)
341 if current
.s
== 3 or current
.s
== 4 then
350 for n
, d
in pairs(current
.n
) do
351 if n
.s
== 0 or n
.s
== 3 then
352 -- Haven't visited this node yet.
357 n
.s
= n
.s
== 3 and 4 or 1
359 local mn
, mx
= 1, #open
+1
362 local m
= floor((mn
+mx
)*0.5)
364 if open
[m
].g
> g
then
371 table.insert(open
, mn
, n
)
372 elseif n
.s
== 1 or n
.s
== 4 then
378 local mn
, mx
= 1, #open
381 local m
= floor((mn
+mx
)*0.5)
382 if open
[m
].g
> og
then
389 while open
[mn
] ~= n
do
395 table.remove(open
, mn
)
398 local m
= floor((mn
+mx
)*0.5)
400 if open
[m
].g
> g
then
408 table.insert(open
, mn
, n
)
417 local function Graph_DoFullSearch(self
, end_list
)
418 local open
= self
.open
419 local end_count
= #end_list
422 local current
= table.remove(open
)
424 if current
.s
== 3 or current
.s
== 4 then
425 if end_count
== 1 then
426 for i
= 1,#removed
do
427 table.insert(end_list
, table.remove(removed
))
432 for i
= 1,end_count
do
433 if end_list
[i
] == current
then
434 table.insert(removed
, table.remove(end_list
, i
))
439 end_count
= end_count
- 1
446 for n
, d
in pairs(current
.n
) do
447 if n
.s
== 0 or n
.s
== 3 then
448 -- Haven't visited this node yet.
453 n
.s
= n
.s
== 3 and 4 or 1
455 local mn
, mx
= 1, #open
+1
458 local m
= floor((mn
+mx
)*0.5)
460 if open
[m
].g
> g
then
467 table.insert(open
, mn
, n
)
468 elseif n
.s
== 1 or n
.s
== 4 then
474 local mn
, mx
= 1, #open
477 local m
= floor((mn
+mx
)*0.5)
478 if open
[m
].g
> og
then
485 while open
[mn
] ~= n
do
491 table.remove(open
, mn
)
494 local m
= floor((mn
+mx
)*0.5)
496 if open
[m
].g
> g
then
504 table.insert(open
, mn
, n
)
510 for i
, n
in ipairs(end_list
) do
511 QuestHelper
:TextOut(i
..") Failed to reach: "..n
.name
..", s="..n
.s
)
514 for i
= 1,#removed
do
515 table.insert(end_list
, table.remove(removed
))
518 for i
, n
in ipairs(end_list
) do
519 QuestHelper
:TextOut(i
..") End node: "..n
.name
..", s="..n
.s
)
522 QuestHelper
:Error("Boom!")
524 for i
= 1,#removed
do
525 table.insert(end_list
, table.remove(removed
))
529 local function propLinks(node
)
532 for n
in pairs(node
.n
) do
538 function Graph_SanityCheck(self
)
539 for i
= 1,#self
.nodes
do
540 for _
, n
in ipairs(self
.nodes
) do
544 propLinks(self
.nodes
[i
])
546 for _
, n
in ipairs(self
.nodes
) do
548 QuestHelper
:TextOut((n
.name
or "unknown").." isn't reachable from "..(self
.nodes
[i
].name
or "unknown"))
554 function QuestHelper
:CreateGraph()
555 local graph
= self
:CreateTable()
556 graph
.nodes
= self
:CreateTable()
557 graph
.end_nodes
= self
:CreateTable()
558 graph
.open
= self
:CreateTable()
560 graph
.CreateNode
= Graph_CreateNode
561 graph
.DestroyNode
= Graph_DestroyNode
562 graph
.Reset
= Graph_Reset
564 graph
.PrepareSearch
= Graph_PrepareSearch
566 graph
.AddRouteStartNode
= Graph_AddRouteStartNode
567 graph
.DoRouteSearch
= Graph_DoRouteSearch
568 graph
.Search
= Graph_Search
569 graph
.SanityCheck
= Graph_SanityCheck
571 -- These don't deal with finding paths and instead only care about finding distances.
572 graph
.AddStartNode
= Graph_AddStartNode
573 graph
.DoSearch
= Graph_DoSearch
574 graph
.DoFullSearch
= Graph_DoFullSearch
579 function QuestHelper
:ReleaseGraph(graph
)
581 self
:ReleaseTable(graph
.nodes
)
582 self
:ReleaseTable(graph
.end_nodes
)
583 self
:ReleaseTable(graph
.open
)
584 self
:ReleaseTable(graph
)
587 QuestHelper
.world_graph
= QuestHelper
:CreateGraph()