fix the tooltips not going away
[QuestHelper.git] / graph.lua
blob8e307eb3c7730cf7f0289f9aba31b6e9d46f0ffc
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)
9 if first ~= last then
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)
16 first.g = 0
17 first.s = 2
19 while #open > 0 do
20 local current = table.remove(open)
22 if current == last then
23 first.p = nil
24 return true
25 end
27 current.s = 2
28 local cd = current.g
30 for n, d in pairs(current.n) do
31 if n.s == 0 then
32 -- Haven't visited this node yet.
33 local g = cd+d
34 n.g = g
35 n.s = 1
36 n.p = current
38 local mn, mx = 1, #open+1
40 while mn ~= mx do
41 local m = floor((mn+mx)*0.5)
43 if open[m].g > g then
44 mn = m+1
45 else
46 mx = m
47 end
48 end
50 table.insert(open, mn, n)
51 elseif n.s == 1 then
52 local g = cd+d
53 if g < n.g then
54 n.g = g
55 n.p = current
56 local mn, mx = 1, #open
58 while mn ~= mx do
59 local m = floor((mn+mx)*0.5)
60 if open[m].g > g then
61 mn = m+1
62 else
63 mx = m
64 end
65 end
67 while open[mn] ~= n do
68 mn = mn + 1
69 end
70 mx = #open
71 table.remove(open, mn)
73 while mn ~= mx do
74 local m = floor((mn+mx)*0.5)
76 if open[m].g > g then
77 mn = m+1
78 else
79 mx = m
80 end
81 end
83 table.insert(open, mn, n)
84 end
85 end
86 end
87 end
88 end
89 last.p = nil
90 return first == last
91 end
93 local function sanity(list, node)
94 local last = nil
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)
104 last = n.g
105 if n == node then
106 contains = true
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)
126 return 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)
136 break
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
153 n.p = nil
155 if n.s == 3 then
156 n.s = 4
157 elseif n.s == 0 then
158 n.s = 1
159 else
160 local og = n.g
161 if g < og then
162 local mn, mx = 1, #open
164 while mn ~= mx do
165 local m = floor((mn+mx)*0.5)
166 if open[m].g > og then
167 mn = m+1
168 else
169 mx = m
173 while open[mn] ~= n do
174 mn = mn + 1
177 table.remove(open, mn)
178 else
179 return -- Don't want to insert the node a second time.
183 local mn, mx = 1, #open+1
185 while mn ~= mx do
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
190 mn = m+1
191 else
192 mx = m
196 table.insert(open, mn, n)
198 n.g = g
201 local function Graph_DoRouteSearch(self, end_list)
202 local open = self.open
203 local end_count = #end_list
205 while #open > 0 do
206 local current = table.remove(open)
208 if current.s == 3 or current.s == 4 then
209 current.s = 2
210 return current
213 current.s = 2
215 local cd = current.g
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.
220 local g = cd+d
221 n.p = current
222 n.g = g
224 n.s = n.s == 3 and 4 or 1
226 local mn, mx = 1, #open+1
228 while mn ~= mx do
229 local m = floor((mn+mx)*0.5)
231 if open[m].g > g then
232 mn = m+1
233 else
234 mx = m
238 table.insert(open, mn, n)
239 elseif n.s == 1 or n.s == 4 then
240 local g = cd+d
241 local og = n.g
242 if g < og then
243 n.p = current
245 local mn, mx = 1, #open
247 while mn ~= mx do
248 local m = floor((mn+mx)*0.5)
249 if open[m].g > og then
250 mn = m+1
251 else
252 mx = m
256 while open[mn] ~= n do
257 mn = mn + 1
260 mx = #open
262 table.remove(open, mn)
264 while mn ~= mx do
265 local m = floor((mn+mx)*0.5)
267 if open[m].g > g then
268 mn = m+1
269 else
270 mx = m
274 n.g = g
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
287 n.s = 0
291 local function Graph_AddStartNode(self, n, g, end_list)
292 local open = self.open
294 n.p = n
296 if n.s == 3 then
297 n.s = 4
298 elseif n.s == 0 then
299 n.s = 1
300 else
301 local og = n.g
302 if g < og then
303 local mn, mx = 1, #open
305 while mn ~= mx do
306 local m = floor((mn+mx)*0.5)
307 if open[m].g > og then
308 mn = m+1
309 else
310 mx = m
314 while open[mn] ~= n do
315 mn = mn + 1
318 table.remove(open, mn)
319 else
320 return -- Don't want to insert the node a second time.
324 local mn, mx = 1, #open+1
326 while mn ~= mx do
327 local m = floor((mn+mx)*0.5)
329 if open[m].g > g then
330 mn = m+1
331 else
332 mx = m
336 table.insert(open, mn, n)
338 n.g = g
341 local function Graph_DoSearch(self, end_list)
342 local open = self.open
343 local end_count = #end_list
345 while #open > 0 do
346 local current = table.remove(open)
348 if current.s == 3 or current.s == 4 then
349 current.s = 2
350 return current
353 current.s = 2
355 local cd = current.g
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.
360 local g = cd+d
361 n.g = g
362 n.p = current.p
364 n.s = n.s == 3 and 4 or 1
366 local mn, mx = 1, #open+1
368 while mn ~= mx do
369 local m = floor((mn+mx)*0.5)
371 if open[m].g > g then
372 mn = m+1
373 else
374 mx = m
378 table.insert(open, mn, n)
379 elseif n.s == 1 or n.s == 4 then
380 local g = cd+d
381 local og = n.g
382 if g < og then
383 n.p = current.p
385 local mn, mx = 1, #open
387 while mn ~= mx do
388 local m = floor((mn+mx)*0.5)
389 if open[m].g > og then
390 mn = m+1
391 else
392 mx = m
396 while open[mn] ~= n do
397 mn = mn + 1
400 mx = #open
402 table.remove(open, mn)
404 while mn ~= mx do
405 local m = floor((mn+mx)*0.5)
407 if open[m].g > g then
408 mn = m+1
409 else
410 mx = m
414 n.g = g
415 table.insert(open, mn, n)
422 local removed = {}
424 local function Graph_DoFullSearch(self, end_list)
425 local open = self.open
426 local end_count = #end_list
428 while #open > 0 do
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))
436 return
439 for i = 1,end_count do
440 if end_list[i] == current then
441 table.insert(removed, table.remove(end_list, i))
442 break
446 end_count = end_count - 1
449 current.s = 2
451 local cd = current.g
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.
456 local g = cd+d
457 n.g = g
458 n.p = current.p
460 n.s = n.s == 3 and 4 or 1
462 local mn, mx = 1, #open+1
464 while mn ~= mx do
465 local m = floor((mn+mx)*0.5)
467 if open[m].g > g then
468 mn = m+1
469 else
470 mx = m
474 table.insert(open, mn, n)
475 elseif n.s == 1 or n.s == 4 then
476 local g = cd+d
477 local og = n.g
478 if g < og then
479 n.p = current.p
481 local mn, mx = 1, #open
483 while mn ~= mx do
484 local m = floor((mn+mx)*0.5)
485 if open[m].g > og then
486 mn = m+1
487 else
488 mx = m
492 while open[mn] ~= n do
493 mn = mn + 1
496 mx = #open
498 table.remove(open, mn)
500 while mn ~= mx do
501 local m = floor((mn+mx)*0.5)
503 if open[m].g > g then
504 mn = m+1
505 else
506 mx = m
510 n.g = g
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)
537 if node.s ~= 1 then
538 node.s = 1
539 for n in pairs(node.n) do
540 propLinks(n)
545 function Graph_SanityCheck(self)
546 for i = 1,#self.nodes do
547 for _, n in ipairs(self.nodes) do
548 n.s = 0
551 propLinks(self.nodes[i])
553 for _, n in ipairs(self.nodes) do
554 if n.s ~= 1 then
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
583 return graph
586 function QuestHelper:ReleaseGraph(graph)
587 graph:Reset()
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()