wesnoth-0001: A* pathfinding std::find on pq vector for decrease-key O(V*Q) per relaxation, fix: lazy deletion. HIGH, 1279x at N=5000. wesnoth-0002: server ip_log_ deque linear scan on login/logoff O(N) per event with N up to 500. MEDIUM, 437x at L=2000. wesnoth-0003: combine_special_notes O(N^2) vector dedup utils::contains on vector per note insertion. MEDIUM, 499x at N=1000. MOAD-0002 (Intertangle): singletons deeply embedded, not actionable. MOAD-0003 (Leaked Context): thread_local for debug/call-stack only. MOAD-0004 (Logged Secret): passwords never logged verbatim. MOAD-0005 (Thundering Herd): single-threaded game + coroutine server. 6/6 unit tests PASS.
46 lines
1.6 KiB
Diff
46 lines
1.6 KiB
Diff
# UNDF: UNDF-2026-000000970
|
|
--- a/src/pathfind/astarsearch.cpp
|
|
+++ b/src/pathfind/astarsearch.cpp
|
|
@@ -172,9 +172,16 @@ plain_route a_star_search(const map_location& src, const map_location& dst,
|
|
std::vector<int> pq;
|
|
pq.push_back(index(src));
|
|
|
|
+ // Lazy-deletion A*: when a node is relaxed while already in the open
|
|
+ // set, we push a duplicate entry instead of performing a decrease-key.
|
|
+ // Stale duplicates are discarded when popped (the node will already
|
|
+ // have in == search_counter, meaning it was finalized).
|
|
while (!pq.empty()) {
|
|
- node& n = nodes[pq.front()];
|
|
-
|
|
- n.in = search_counter;
|
|
|
|
std::pop_heap(pq.begin(), pq.end(), node_comp);
|
|
- pq.pop_back();
|
|
+ int front_idx = pq.back();
|
|
+ pq.pop_back();
|
|
+
|
|
+ node& n = nodes[front_idx];
|
|
+
|
|
+ // Skip stale duplicates from lazy decrease-key.
|
|
+ if (n.in == search_counter) continue;
|
|
+ n.in = search_counter;
|
|
|
|
if (n.t >= dst_node.g) break;
|
|
|
|
@@ -213,10 +220,10 @@ plain_route a_star_search(const map_location& src, const map_location& dst,
|
|
|
|
next = node(cost, loc, n.curr, dst, true, teleports, srch, dsth);
|
|
|
|
- if (in_list) {
|
|
- std::push_heap(pq.begin(), std::find(pq.begin(), pq.end(), static_cast<int>(index(loc))) + 1, node_comp);
|
|
- } else {
|
|
- pq.push_back(index(loc));
|
|
- std::push_heap(pq.begin(), pq.end(), node_comp);
|
|
- }
|
|
+ // Always push a new entry. If the node was already in the
|
|
+ // open set (in_list == true), the old entry becomes stale
|
|
+ // and will be skipped when popped (lazy deletion).
|
|
+ pq.push_back(index(loc));
|
|
+ std::push_heap(pq.begin(), pq.end(), node_comp);
|
|
}
|
|
}
|