Why is the cycle endless? - c++

Hi guys!
I want to switch to UE4 and am now trying to repeat the function of finding a way by waypoints, it works well in Unity, but there were problems in C ++. the function turned out with an infinite loop, as I understand it, openList cannot become empty. my c ++ knowledge is not enough to solve the problem. I will be glad of any help!
TArray<FVector> UWaypointsPathfinding::GetPath(UWaypoint* startNode, UWaypoint* goalNode)
{
UWaypoint* beginNode = startNode;
set<UWaypoint*> openList;
vector<UWaypoint*> closedList;
openList.insert(startNode);
startNode->previous = nullptr;
startNode->distance = 0;
while (!openList.empty())
{
startNode = *openList.begin();
openList.erase(openList.begin());
float dist = startNode->distance;
closedList.push_back(startNode);
if(startNode == goalNode) break;
int l = startNode->nearest.Num();
for (int i = 0; i < l; i++)
{
UWaypoint* node = startNode->nearest[i]->FindComponentByClass<UWaypoint>();
if(find(closedList.begin(),closedList.end(),node) != closedList.end() || openList.find(node) != openList.end())
continue;
node->previous = startNode;
node->distance = dist + FVector::Dist(node->GetOwner()->GetActorLocation(), startNode->GetOwner()->GetActorLocation());
node->distance += FVector::Dist(node->GetOwner()->GetActorLocation(), goalNode->GetOwner()->GetActorLocation());
openList.insert(startNode);
}
}
// create path...
return TArray<FVector>();
}
supposedly the problem is in this piece
if(startNode == goalNode) break;
int l = startNode->nearest.Num();
for (int i = 0; i < l; i++)
{
UWaypoint* node = startNode->nearest[i]->FindComponentByClass<UWaypoint>();
if(find(closedList.begin(),closedList.end(),node) != closedList.end() || openList.find(node) != openList.end())
continue;
node->previous = startNode;
node->distance = dist + FVector::Dist(node->GetOwner()->GetActorLocation(), startNode->GetOwner()->GetActorLocation());
node->distance += FVector::Dist(node->GetOwner()->GetActorLocation(), goalNode->GetOwner()->GetActorLocation());
openList.insert(startNode);
}

The logic is strange so this is a mistype probably.
You insert startNode to openList at the beginning, then erase it in the loop and insert again. So the openList will always have a single member startNode and all cycles are identical.
Perhaps you meant openList.insert(node); instead of openList.insert(startNode); at the last line of the loop?

Related

Breadth First Search segfault

I have a BFS that is supposed to solve a maze that currently only solves short mazes and returns a segfault for other mazes
this algorithm is supposed to add to a vector a path as long as there are no junctions and if there are any junctions it is supposed to create two equally long vectors each following a single path.
std::vector<MazeNode> solveBFS(Maze &a_maze){
MazeNode * NextNode = a_maze.getFirstNode();
std::vector<MazeNode*> Final;
std::vector<MazeNode> Finals;
std::queue<vector<MazeNode*> > Qvec;
NextNode->setVisited();
Final.push_back(NextNode);
Qvec.push(Final);
while(!Qvec.empty() && Qvec.front().at(Qvec.front().size()-1) != a_maze.getLastNode()){
cout << *Qvec.front().at(Qvec.front().size()-1) << endl;
std::vector<MazeNode*> TempV = Qvec.front();
MazeNode * Top = TempV.back();
Qvec.pop();
for(directions::nesw dir = directions::NORTH; dir < directions::WEST; dir = directions::nesw(dir + 1)){
if(canTravel(Top->getDirectionNode(dir))){
NextNode = Top->getDirectionNode(dir);
NextNode->setVisited();
NextNode->setVisited();
TempV.push_back(NextNode);
Qvec.push(TempV);
TempV.pop_back();
}
}
}
for(int i = 0; i < Qvec.front().size(); i++){
Finals.push_back(* Qvec.front()[i]);
}
return Finals;
}

need to find the min distance and make a route

The graph:
and how the points are connected:
the file how points are connected are the output i have . The expected output should be 1<->216 , 23<->157 115<->157 and then 115<->216 . The order doesn't matter but those points should be connected this way
Let me ask you a question.
I have the following code:
for (int i = 0; i < values.size()-1;i++)
{
int result = 0;
double Min2 = DBL_MAX;
int x = 0;
for (int j = i+1; j < values.size(); j++)
{
/*if (visited[j] == false)*/
{
distance = sqrt(pow((values[i].x2 - values[j].x2), 2) + pow((values[i].y2 - values[j].y2), 2));
if (distance < Min2 && distance != 0)
{
Min2 = distance;
x = j;
}
}
}
If you look at the graph the left first node is 1 then goes 216 then 115 then 157 and then 23. I have the right connection except for 216-115 but instead of it connects 216-157. Why does it ignore or min distance won't help. I tried to use flag( like if visited or not)the same result. All nodes work , just this one doesn't want to be connected right.
The logic of the code seems a bit odd...
for (int i = 0; i < values.size()-1;i++) {
int result = 0;
double Min2 = DBL_MAX;
int x = 0;
for (int j = i+1; j < values.size(); j++) {
iterating till size()-1 seems like you assume that the relation "closest neighbour" is commutative, but it is not. Consider this example:
a b c
a has b as closest node and (by chance) also b has a as closest node, but c has b as closest node and this connection you would miss.
Further, starting the second loop at i+1 seems rather odd, as it assumes that the points in the vector are already ordered (if this would be the case, then whats the point of searching the closest nodes?).
If you know already, that the nodes are along a route, then I would do it like this:
1) start with the first node n0 in the route (its a bit more complicated if you dont know this node)
2) find the closest node to n0 call it n1
3) continue to find the closest node to ni among the nodes that are not yet connected to the route, call it ni+1
4) repeat 3) until you reach the end of the route.
I have the impression, that you dont understand the difference between those steps and your code. I dont like to give up, so I will try to explain again in a less pseudo way:
int currentNode = startNode; // as mentioned before, if you dont know
// this its a bit more involved
std::vector<int> route;
route.push_back(currentNode);
while (currentNode != endNode) { // also knowing the last node of the route helps...
double minDistance = std::numeric_limits<double>::max();
int nextNode = -1;
for (int i=0;i<nodes.size();i++) {
if (std::find(route.begin(), route.end(), i) == route.end()){
double distance = getDistance(currentNode,i);
if (distance < minDistance) {
minDistance = distance;
nextNode = i;
}
}
}
route.push_back(nextNode);
currentNode = nextNode;
}
Your outer loop shouldnt iterate through all nodes, if you actually want to find only that one route. Also you have to remember nodes that are already in the route (in case each node should appear only once and you dont want a closed loop).
for (int i = 0; i < values.size();i++)
{
int result = 0;
double Min2 = DBL_MAX;
int x = 0;
for (int j =0; j < values.size(); j++)
{
/*if (visited[j] == false)*/
{
distance = sqrt(pow((values[i].x2 - values[j].x2), 2) + pow((values[i].y2 - values[j].y2), 2));
if (distance < Min2 && distance != 0)
{
Min2 = distance;
x = j;
}
}
}
/*visited[i] = true;*/

Need to shuffle a linked list of a deck of cards, getting an infinite loop

I am writing code for a class and I need to shuffle a desk of linked list of cards in C++. I am basically having the code swap two cards position many times in order to randomize their order. However, I'm having a lot of trouble getting the pointers right and I end up in an infinite loop of a card pointing to itself when I try to print it out. I was wondering if anybody can see anything wrong.
void deck::shuffle() //shuffles deck linked list of 52 card objects
{
node<card> *curr1 = new node<card>;
node<card> *curr2 = new node<card>;
node<card> *prev1 = new node<card>;
node<card> *prev2 = new node<card>;
node<card> temp1;
node<card> temp2;
randomNumber rand;
int random1, random2;
for (int i = 0; i < 100; i++)
{
curr1 = front;
curr2 = front;
prev1 = NULL;
prev2 = NULL;
random1 = rand.random(51);
random2 = rand.random(52 - random1) + random1;
while (random1 == random2)
random2 = rand.random(52 - random1) + random1;
for (int j = 0; j < random1; j++)
{
prev1 = curr1;
curr1 = curr1->next;
}
for (int k = 0; k < random2; k++)
{
prev2 = curr2;
curr2 = curr2->next;
}
temp1 = *curr1;
temp1.next = curr1->next;
if (curr1->next == curr2)
{
curr1->next = curr2->next;
curr2->next = curr1;
}
else
{
curr1->next = curr2->next;
curr2->next = temp1.next;
}
if (prev2 == NULL)
front = curr1;
else
prev2->next = curr1;
if (prev1 == NULL)
front = curr2;
else
prev1->next = curr2;
}
}
I'll give you pseudo code because I don't like writing people's homeworks. It shouldn't be difficult to translate to code though.
srand(time(NULL)); //seeds the random number generator
ran1 = rand() % NUM_ITEMS_IN_LIST; //otherwise you can get 9989798690
ran2 = rand() % ...
Node* firstNode = head;
for (int i=1 i <= ran1; i++)
{
firstNode = firstNode->next;
}
//same for second node
swap(firstNode, secondNode);
First thing first, there are lots of things that are wrong with your code:
you initialize curr1, curr2, prev1 and prev2 by calling new, but then you directly assign them (meaning that you have a memory leak in addition to the useless initialization)
random1 is an integer between 0 and 51 (if rand.random() does what I assume it does), which means that rand.random(52 - random1) + random1 goes from 0 to 52. I'm assuming that you are trying to get random1 and random2 between 0 and 51, with random1 < random2, so this is not what you want: try random1 = rand.random(50); and random2 = rand.random(50 - random1) + random1 + 1; (that will also allow you to skip the while).
temp1.next = curr1->next; is useless after temp1 = *curr1; (also, you don't really need temp1 but only an address to store curr1->next, and you never use temp2)
That being said, to get you out of your trouble:
It seems to me that the only way you can enter an infinite loop is if while (random1 == random2) stays true, and it also seems that a card can only point to itself after curr1->next = curr2->next; with curr2->next == curr1. Since those things are not supposed to happen, I would check if the problem comes from rand.random() if I were you.
If you really want to understand what's going on, printing things out won't be enough help. The usual thing to do is to use a debugger: set a breakpoint and execute the program instruction by instruction to see what's really happening (it also allows you to look at the values of the variables). If you use an IDE, they usually include a debugger and make the use of breakpoint very easy (you can find plenty information on how to do that by googling "breakpoint" and the name of your IDE).

Function to manipulate a string ("abcdef" -> "faebdc")

Hi everyone I'm working on a function to manipulating any string in this following manner.
"abc" -> "cab"
"abcd" -> "dacb"
"abcdef" -> "faebdc"
"divergenta" -> "adtinveerg"
... and so on.
This is the code I've come up with so far. I think it does the job but I think the code and solution is kind of ugly and I'm not sure if it's fail proof and if it is working properly for every given case. I would highly appreciate any input on this code or any examples on how you would write this function. I beg you to bear in mind that I'm very much a n00b so don't go too hard on me.
string transformer(string input) {
string temp;
int n = 0;
int m = (input.length() -1);
for( int i = 0; i < input.length(); i++) {
temp += input[m];
if (input[m] == input[n]) {
break;
}
else {
temp += input[n];
}
n += 1;
m -= 1;
if ( temp.length() == input.length() ) {
break;
}
}
return temp; }
You have three problems.
Try it with "abbba". If the result isn't what you want, then this conditional:
if (input[m] == input[n]) {
break;
}
is just plain wrong.
Look at the other conditional:
if ( temp.length() == input.length() ) {
break;
}
You're adding two characters at a time to temp. What if input has odd length?
Suppose that works correctly. Consider the loop:
for( int i = 0; i < input.length(); i++) {
...
if ( temp.length() == input.length() ) {
break;
}
}
That loop will never terminate in the for statement. You might as well do it this way:
while( temp.length() < input.length() ) {
...
}
Once that's all working correctly, you should look into iterators.
This function just walks two indices toward the center until they meet or pass each other. The last if block handles the case of an odd length input string. It works for all your test cases on ideone.com
std::string transformer(const std::string& input)
{
std::string temp;
int i = 0;
int j = input.length() - 1;
while (i < j) {
temp += input[j--];
temp += input[i++];
}
if (i == j) {
temp += input[i];
}
return temp;
}
std::string transformer(const std::string& input) {
std::string res(input.length(), '0');
for (int i = 0; i < input.length(); ++i) {
res[i] = input[ i % 2 == 0 ? input.length() - (i/2) - 1 : (i/2) ];
}
return res;
}
Unfortunately if (input[m] == input[n]) will make sure that if the first and last characters are the same, it immediately quits after the first character is processed.
I'd do this with std::string::iterator and std::string::reverse_iterator:
auto it = input.begin();
auto rit = input.rbegin();
std::string temp;
for (size_t i = 0; i < input.length()/2; ++i) {
temp += *rit++;
temp += *it++;
}
The logic for handling empty and odd-length input is left for you to do, shouldn't be too hard. (Input of length 1 is also a special case)
I would use pointers instead of indexes to do this.
So you have a pointer the reading the edges and you keep swapping them with each iteration.
It will also make it faster.
I think this should work, but I can't remember how to make an array of const char pointers. Can anyone help me with that step?
string transformer(string input) {
std::string temp;
const char *front, *back;
for (*front = input.c_str(), *back = front + input.length() - 1; front < back ; front++, back--) {
temp += *back;
temp += *front;
}
if (front == back)
temp += *front;
return temp;
}
(using the same method as #Blastfurnace, but skipping unnecessary indexes.)

QuickSort in c++

I'm trying to get quicksort working to sort an array of 7000 strings into alphabetical order, but all i'm getting is a blank output file. It works fine with my bubblesort method, but not with this. I'm sure it's an obvious mistake, but i can't pin-point it.
void ArrayStorage::quicksort(int first, int last, string list[])
{
int middle, p, index;
string temp, partition;
if (first < last)
{
middle = int(first + last)/2;
temp = list[middle];
list[middle] = list[first];
list[first] = temp;
partition = list[first];
p = first;
for (index = first + 1; index <= last; index++)
{
if(list[index] < partition)
{
p = p + 1;
temp = list[index];
list[index] = list[p];
list[p] = temp;
}
}
temp = list[first];
list[first] = list[p];
list[p] = temp;
quicksort(first, p - 1, list);
quicksort(p + 1, last, list);
}
}
I call the method like this:
quicksort(0,GetSize() -1,namesArray);
How about using the built in quicksort?:
std::sort(&namesArray[0], &namesArray[GetSize()]);
Well as the principle in each loop of quick sort is to make the temp variable in the position that all elements less than it are put left to temp and greater ones on the right. So that must be a loop contains both rightwards iteration to search if there's any number greater than temp and leftwards vice versa. If there is, put the current content to the other side then iterating from the other side until the overall iteration of the list. After the loop all elements less than temp should be on the left while greater ones on right.
temp = list[first];
int f = first, l = last;
while (f < l)
{
while ((f <= l) && (list[l] < temp)) l--;
if (f <= l)
{
list[f] = list[l];
f++;
}
while ((f <= l) && (list[f] > temp)) f++;
if (f <= l)
{
list[l] = list[f];
l--;
}
}
This piece of code should work.(I don't have the compiler on this computer) If it does, try to invoke the function itself recursively.
In addition there's an advice. As many people's recommended you, trying debug and solve the problem yourself.
Hope it helps