Skip to content

Commit

Permalink
Pathfinding: Precomputeportal nodes for A Star
Browse files Browse the repository at this point in the history
  • Loading branch information
jere8184 committed Nov 20, 2024
1 parent 40f8fc4 commit b286c0c
Showing 1 changed file with 126 additions and 156 deletions.
282 changes: 126 additions & 156 deletions libopenage/datastructure/pairing_heap.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,13 @@ class PairingHeapNode {
// it must not have siblings as they will get lost.

new_child->prev_sibling = nullptr;
new_child->next_sibling = this->child;
new_child->next_sibling = this->first_child;

if (this->child != nullptr) {
this->child->prev_sibling = new_child;
if (this->first_child != nullptr) {
this->first_child->prev_sibling = new_child;
}

this->child = new_child;
this->first_child = new_child;
new_child->parent = this;
}

Expand Down Expand Up @@ -156,10 +156,10 @@ class PairingHeapNode {
*/
void loosen() {
// release us from some other node
if (this->parent and this->parent->child == this) {
if (this->parent and this->parent->first_child == this) {
// we are child
// make the next sibling child
this->parent->child = this->next_sibling;
this->parent->first_child = this->next_sibling;
}
// if we have a previous sibling
if (this->prev_sibling != nullptr) {
Expand All @@ -179,7 +179,7 @@ class PairingHeapNode {
}

private:
this_type *child = nullptr;
this_type *first_child = nullptr;
this_type *prev_sibling = nullptr;
this_type *next_sibling = nullptr;
this_type *parent = nullptr; // for decrease-key and delete
Expand Down Expand Up @@ -230,12 +230,89 @@ class PairingHeap final {
}

/**
* returns and removes the smallest item on the heap.
* returns the smallest item on the heap and deletes it.
* also known as delete_min.
* _________
* Ω(log log n), O(2^(2*√log log n'))
* caller must eventually either add node back to heap or delete it
*/
T pop() {
element_t poped_node = this->pop_node();
T data = std::move(poped_node->data);
delete poped_node;
if (this->root_node == nullptr) {
throw Error{MSG(err) << "Can't pop an empty heap!"};
}

// 0. remove tree root, it's the minimum.
element_t ret = this->root_node;

if (!this->nodes.erase(ret)) {
throw Error{MSG(err) << "didn't remove node"};
}

this->node_count -= 1;
element_t current_sibling = this->root_node->first_child;
this->root_node = nullptr;

// 1. link root children pairwise, last node may be alone
element_t first_pair = nullptr;
element_t previous_pair = nullptr;

while (current_sibling != nullptr) [[unlikely]] {
element_t link0 = current_sibling;
element_t link1 = current_sibling->next_sibling;

// pair link0 and link1
if (link1 != nullptr) {
// get the first sibling for next pair, just in advance.
current_sibling = link1->next_sibling;

// do the link: merges two nodes, smaller one = root.
element_t link_root = link0->link_with(link1);
link_root->parent = nullptr;

if (previous_pair == nullptr) {
// this was the first pair
first_pair = link_root;
first_pair->prev_sibling = nullptr;
}
else {
// store node as next sibling in previous pair
previous_pair->next_sibling = link_root;
link_root->prev_sibling = previous_pair;
}

previous_pair = link_root;
link_root->next_sibling = nullptr;
}
else {
// link0 is the last and unpaired root child.
link0->parent = nullptr;
if (previous_pair == nullptr) {
// link0 was the only node
first_pair = link0;
link0->prev_sibling = nullptr;
}
else {
previous_pair->next_sibling = link0;
link0->prev_sibling = previous_pair;
}
link0->next_sibling = nullptr;
current_sibling = nullptr;
}
}


// 2. then link remaining trees to the last one, from right to left
if (first_pair != nullptr) {
this->root_node = first_pair->link_backwards();
}

// (to find those two lines, 14h of debugging passed)
ret->loosen();
ret->first_child = nullptr;

// and it's done!
T data = std::move(ret->data);
delete ret;
return data;
}

Expand Down Expand Up @@ -283,27 +360,44 @@ class PairingHeap final {
*
* O(1) (but slower than decrease), and O(pop) when node is the root.
*/
void update(const element_t &node) {
void update(element_t &node) {
if (node != this->root_node) [[likely]] {
this->unlink_node(node);
this->push_node(node);
node = this->push(this->remove_node(node));
}
else {
// it's the root node, so we just pop and push it.
this->push_node(this->pop_node());
node = this->push(this->pop());
}
}


/**
* Remove node from tree, return its data and destroy the node.
* O(pop_node)
* remove a node from the heap. Return its data.
*
* If the item is the current root, just pop().
* else, cut the node from its parent, pop() that subtree
* and merge these trees.
*
* O(pop_node)
*/
T remove_node(element_t &node) {
this->unlink_node(node);
T data = std::move(node->data);
delete node;
return data;
T remove_node(const element_t &node) {
if (node == this->root_node) {
return this->pop();
}
else {
node->loosen();

element_t real_root = this->root_node;
this->root_node = node;
T data = this->pop();

element_t new_root = this->root_node;
this->root_node = real_root;

if (new_root != nullptr) {
this->root_insert(new_root);
}
return data;
}
}

/**
Expand All @@ -316,9 +410,6 @@ class PairingHeap final {
delete node;
}
this->nodes.clear();

#if OPENAGE_PAIRINGHEAP_DEBUG
#endif
}

/**
Expand Down Expand Up @@ -378,23 +469,23 @@ class PairingHeap final {
}
}

if (root->child) {
if (root->child == root->next_sibling) {
throw Error{ERR << "child is next_sibling"};
if (root->first_child) {
if (root->first_child == root->next_sibling) {
throw Error{ERR << "first_child is next_sibling"};
}
if (root->child == root->prev_sibling) {
throw Error{ERR << "child is prev_sibling"};
if (root->first_child == root->prev_sibling) {
throw Error{ERR << "first_child is prev_sibling"};
}
if (root->child == root->parent) {
throw Error{ERR << "child is parent"};
if (root->first_child == root->parent) {
throw Error{ERR << "first_child is parent"};
}
}

if (root->parent) {
if (found_nodes.find(root->parent) == std::end(found_nodes)) {
throw Error{ERR << "parent node is not known"};
}
element_t child = root->parent->child;
element_t child = root->parent->first_child;
element_t lastchild;

bool foundvianext = false, foundviaprev = false;
Expand Down Expand Up @@ -492,43 +583,12 @@ class PairingHeap final {
}

private:
/**
* Unlink a node from the heap.
*
* If the item is the current root, just pop().
* else, cut the node from its parent, pop() that subtree
* and merge these trees.
*
* O(pop_node)
* caller must eventually add node back to heap or delete node
*/
void unlink_node(const element_t &node) {
if (node == this->root_node) {
this->pop_node();
}
else {
node->loosen();

element_t real_root = this->root_node;
this->root_node = node;
this->pop_node();

element_t new_root = this->root_node;
this->root_node = real_root;

if (new_root != nullptr) {
this->root_insert(new_root);
}
}
}


void walk_tree(const element_t &root,
const std::function<void(const element_t &)> &func) const {
func(root);

if (root) {
auto node = root->child;
auto node = root->first_child;
while (true) {
if (not node) {
break;
Expand Down Expand Up @@ -560,96 +620,6 @@ class PairingHeap final {
}


/**
* returns the smallest item on the heap and deletes it.
* also known as delete_min.
* _________
* Ω(log log n), O(2^(2*√log log n'))
* caller must eventually either add node back to heap or delete it
*/
element_t pop_node() {
if (this->root_node == nullptr) {
throw Error{MSG(err) << "Can't pop an empty heap!"};
}

// 0. remove tree root, it's the minimum.
element_t ret = this->root_node;
element_t current_sibling = this->root_node->child;
this->root_node = nullptr;

// 1. link root children pairwise, last node may be alone
element_t first_pair = nullptr;
element_t previous_pair = nullptr;

while (current_sibling != nullptr) [[unlikely]] {
element_t link0 = current_sibling;
element_t link1 = current_sibling->next_sibling;

// pair link0 and link1
if (link1 != nullptr) {
// get the first sibling for next pair, just in advance.
current_sibling = link1->next_sibling;

// do the link: merges two nodes, smaller one = root.
element_t link_root = link0->link_with(link1);
link_root->parent = nullptr;

if (previous_pair == nullptr) {
// this was the first pair
first_pair = link_root;
first_pair->prev_sibling = nullptr;
}
else {
// store node as next sibling in previous pair
previous_pair->next_sibling = link_root;
link_root->prev_sibling = previous_pair;
}

previous_pair = link_root;
link_root->next_sibling = nullptr;
}
else {
// link0 is the last and unpaired root child.
link0->parent = nullptr;
if (previous_pair == nullptr) {
// link0 was the only node
first_pair = link0;
link0->prev_sibling = nullptr;
}
else {
previous_pair->next_sibling = link0;
link0->prev_sibling = previous_pair;
}
link0->next_sibling = nullptr;
current_sibling = nullptr;
}
}


// 2. then link remaining trees to the last one, from right to left
if (first_pair != nullptr) {
this->root_node = first_pair->link_backwards();
}

this->node_count -= 1;
size_t erase_result = this->nodes.erase(ret);


#if OPENAGE_PAIRINGHEAP_DEBUG
if (1 != erase_result) {
throw Error{ERR << "didn't remove node"};
}
#endif

// (to find those two lines, 14h of debugging passed)
ret->loosen();
ret->child = nullptr;

// and it's done!
return ret;
}


/**
* insert a node into the heap.
*/
Expand Down

0 comments on commit b286c0c

Please sign in to comment.