Nested<const int> SegmentSoup::neighbors() const { if (nodes() && !neighbors_.size()) { Array<int> lengths(nodes()); for(int s=0;s<elements.size();s++) for(int a=0;a<2;a++) lengths[elements[s][a]]++; neighbors_ = Nested<int>(lengths); for(int s=0;s<elements.size();s++) { int i,j;elements[s].get(i,j); neighbors_(i,neighbors_.size(i)-lengths[i]--) = j; neighbors_(j,neighbors_.size(j)-lengths[j]--) = i; } // Sort and remove duplicates if necessary bool need_copy = false; for(int i=0;i<nodes();i++) { RawArray<int> n = neighbors_[i]; sort(n); int* last = std::unique(n.begin(),n.end()); if(last!=n.end()) need_copy = true; lengths[i] = int(last-n.begin()); } if (need_copy) { Nested<int> copy(lengths); for(int i=0;i<nodes();i++) copy[i] = neighbors_[i].slice(0,lengths[i]); neighbors_ = copy; } } return neighbors_; }
// Add an edge from this node to neighbor. void node_impl::add_edge (Supports_Test::Node * neighbor) { degree_ (degree_ () + 1); neighbors_ ().length (neighbors_ ().length () + 1); neighbors_ ()[neighbors_ ().length () - 1] = neighbor; neighbor->_add_ref (); return; }
void node_impl::print (void) { cout << " Name: " << name_ () << endl; cout << " Weight: " << weight_ () << endl; cout << " Degree: " << degree_ () << endl; cout << " Neighbors: " << endl; for (size_t i = 0; i < neighbors_ ().length (); i++) cout << " " << neighbors_ ()[i]->name_ () << endl; }
// Initialize state. node_impl::node_impl (const char * name) { name_ (name); weight_ (0); degree_ (0); neighbors_ ().length (0); }
// Remove the edge from this node to neighbor. void node_impl::remove_edge (Supports_Test::Node * neighbor) { for (unsigned int i = 0; i < neighbors_ ().length (); i++) if (neighbors_ ()[i] == neighbor) { neighbors_ ()[i] = neighbors_ ()[neighbors_ ().length () - 1]; neighbors_ ().length (neighbors_ ().length () - 1); neighbor->_remove_ref (); } }
std::vector<int> Pathfinder::getReachableNodes(int start, int maxDist) const { std::queue<BfsNode> nodeQ; std::vector<int> reachable; nodeQ.emplace(BfsNode{start, 0}); while (!nodeQ.empty()) { const auto &node = nodeQ.front(); if (binary_search(std::begin(reachable), std::end(reachable), node.id)) { nodeQ.pop(); continue; } reachable.push_back(node.id); sort(std::begin(reachable), std::end(reachable)); for (auto nbr : neighbors_(node.id)) { auto cost = node.costSoFar + stepCost_(node.id, nbr); if (cost <= maxDist) { nodeQ.emplace(BfsNode{nbr, cost}); } } nodeQ.pop(); } // AI players use this function when computing possible moves. All else // equal, it looks better if the AI prefers to stand still and attack an // adjacent unit rather than move and attack. Thus, we ensure the unit's // current hex is the first in the list of possible moves. auto iter = lower_bound(std::begin(reachable), std::end(reachable), start); rotate(std::begin(reachable), iter, std::end(reachable)); return reachable; }
std::vector<int> Pathfinder::getPathFrom(int start) const { if (goal_(start)) return {start}; // Record shortest path costs for every node we examine. std::unordered_map<int, AstarNodePtr> nodes; // Maintain a heap of nodes to consider. std::vector<int> open; int goalLoc = -1; AstarNodePtr goalNode; // The heap functions confusingly use operator< to build a heap with the // *largest* element on top. We want to get the node with the *least* cost, // so we have to order nodes in the opposite way. auto orderByCost = [&] (int lhs, int rhs) { return nodes[lhs]->estTotalCost > nodes[rhs]->estTotalCost; }; nodes.emplace(start, make_astar_node(-1, 0, 0)); open.push_back(start); // A* algorithm. Decays to Dijkstra's if estimate function is always 0. while (!open.empty()) { auto loc = open.front(); pop_heap(std::begin(open), std::end(open), orderByCost); open.pop_back(); if (goal_(loc)) { goalLoc = loc; goalNode = nodes[loc]; break; } auto &curNode = nodes[loc]; curNode->visited = true; for (auto n : neighbors_(loc)) { auto nIter = nodes.find(n); auto step = stepCost_(loc, n); if (nIter != nodes.end()) { auto &nNode = nIter->second; if (nNode->visited) { continue; } // Are we on a shorter path to the neighbor node than what // we've already seen? If so, update the neighbor's node data. if (curNode->costSoFar + step < nNode->costSoFar) { nNode->prev = loc; nNode->costSoFar = curNode->costSoFar + step; nNode->estTotalCost = nNode->costSoFar + estimate_(n); make_heap(std::begin(open), std::end(open), orderByCost); } } else { // We haven't seen this node before. Add it to the open list. nodes.emplace(n, make_astar_node(loc, curNode->costSoFar + step, curNode->costSoFar + step + estimate_(n))); open.push_back(n); push_heap(std::begin(open), std::end(open), orderByCost); } } } if (!goalNode) { return {}; } // Build the path from the chain of nodes leading to the goal. std::vector<int> path = {goalLoc}; auto n = goalNode; while (n->prev != -1) { path.push_back(n->prev); n = nodes[n->prev]; } reverse(std::begin(path), std::end(path)); assert(contains(path, start)); return path; }