vector, removing object trouble - c++

I am new to c++ and am currently learning sfml.
I have set up a system that adds one 'Snowpile' object to the vector. But when I keep hitting errors like "can't increment vector past iterator past end" or that it's outside the scope.
std::vector<Snowpile*> snowpiles;
I want it to check every snowpile for the removed2 bool, and delete the ones that do have it.
for (auto s_it = snowpiles.begin(); s_it != snowpiles.end(); s_it++) {
int sindex = std::distance(snowpiles.begin(), s_it);
if (snowpiles[sindex]->getSprite_S().getGlobalBounds().intersects(player.getSpriteP().getGlobalBounds()) && snowpiles[sindex]->melting == false) {
snowpiles[sindex]->melting = true;
}
else if (snowpiles[sindex]->getSprite_S().getGlobalBounds().intersects(player.getSpriteP().getGlobalBounds()) && snowpiles[sindex]->melting == true) {
snowpiles[sindex]->melting = true;
}
else if (!snowpiles[sindex]->getSprite_S().getGlobalBounds().intersects(player.getSpriteP().getGlobalBounds()) && snowpiles[sindex]->melting == true) {
snowpiles[sindex]->melting = false;
}
snowpiles[sindex]->meltedrem(sindex, snowpiles, m_win);
if (snowpiles[sindex]->removed2 == true)
{
cout << "Detected removed 2 at " << sindex << endl;
//delete snowpiles[sindex];
snowpiles.erase(snowpiles.begin() + sindex - 1);
}
}
The melting parts determine whether the player is on top of a snowpile. The meltdrem functions checks for bool 'melting' == true and then proceeds to start the timer. After a few seconds (+ animations) it sets the bool removed2 to true.
I know that at the program at least sees the bools changing, so thats not it.
Am I simply using vector wrong, or do I need to change something in my loop?
The loop is located in the while(window.isOpen()) loop in int main.

For starters it is unclear why there is used the expression
snowpiles.erase(snowpiles.begin() + sindex - 1);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
instead of
snowpiles.erase(snowpiles.begin() + sindex);
^^^^^^^^^^^^^^^^^^^^^^^^^^
if in a comment you wrote
//delete snowpiles[sindex];
You need to increase the iterator in the for loop only when a current object was not removed.
Change the loop the following way
for (auto s_it = snowpiles.begin(); s_it != snowpiles.end(); ) {
//...
if (snowpiles[sindex]->removed2 == true)
{
cout << "Detected removed 2 at " << sindex << endl;
//delete snowpiles[sindex];
s_it = snowpiles.erase( s_it );
}
else
{
++s_it;
}
}

Related

Why does my recursion not return to previous pointer?

I am working on an assignment in which we must create a 20-questions type game from a binary search tree. We read the tree in from a text file that is formatted like this:
Does it walk on 4 legs?
Does it fly?
*centipede?
Is it an insect?
*bird?
*butterfly?
Does it purr?
Does it howl?
*mouse?
*dog?
*cat?
Later, I am going to allow the user to add to this list. At the moment, however, I am unable to accurately read the list into a binary search tree. I have set it up so that (I think) it will use recursion and return to the previous "current" node pointer when it ends a loop of the function. Currently, however, the current node pointer remains the same.
The below function is passed a vector of the strings from the text file.
string line;
string guess;
bool start = true;
void buildTree(vector<string> gameData, Node* current, int &counter)
{
//fill node with question or answer
//recursive:
// add to the left until we encounter an asterisk
// add to the right
line = gameData[counter];
//if a question
if (line[0] != '*')
{
if (current->getData().empty())
{
current->setData(line);
cout << current->getData() << endl;
}
if (!start)
{
//if noChild is empty AND current isn't a guess, go to noChild
if ((current->getNo()->getData().empty())
&& (current->isGuess() == false))
{
current = current->getNo();
}
//otherwise, go to yes
else {
current = current->getYes();
}
}
while (counter < gameData.size())
{
if (!start) { counter++; }
start = false;
buildTree(gameData, current, counter);
}
}
//if a guess
else
{
//if data is full, go to no
if (current->getData().empty() == false)
{
current = current->getNo();
}
//otherwise, go to yes
else
{
//current = current->getYes();
for (int i = 1; i < line.size(); i++)
{
guess.push_back(line[i]);
}
current->setData(guess);
guess.clear();
cout << current->getData() << endl;
counter++;
current->setGuess(true);
}
}
}

Solving 8-Puzzle in C++ with A* results in endless loop

I'm currently trying to solve the 8-Puzzle with the A* search algorithm, but my program gets stuck in an endless loop.
My main searching loop is:
std::vector<Field> Search::AStar(Field &start, Field &goal){
std::cout << "Calculating..." << std::endl;
std::unordered_map<Field, Field> explored;
std::vector<Field> searched;
if (Puzzle::finished(start))
return MakePath(start, start);
std::priority_queue<Field, std::vector<Field>, std::greater<Field>> frontier;
frontier.push(start);
Field current;
Field child;
size_t i = 0;
while (!frontier.empty())
{
current = frontier.top();
frontier.pop();
if (++i > 500)
{
std::cout << "Iteration Error" << std::endl;
return searched;
}
searched.push_back(current);
for (Direction d : Puzzle::Actions(current))
{
child = Puzzle::Action(d, current);
if (Puzzle::finished(child))
{
std::cout << "Found goal!" << std::endl;
return MakePath(explored[child], start);
}
child.CostG = current.CostG + 1; // Make a step
if (!isIn(child, explored) || child.CostG < explored[child].CostG)
{
child.CostH = Puzzle::Heuristic(child, goal); // Calculate Heuristic
child.CostF = child.CostG + child.CostH; // Calculate final costs
frontier.push(child);
explored[child] = child;
explored[child].setParent(&explored[current]);
}
}
}
std::cout << "Error: frontier Empty" << std::endl;
return searched;
}
The vector "searched" is just so that I can see what A* does, and I will delete it as soon as the algorithm works.
The CostG stands for the number of steps done until this point, the CostH are the estimated minimum (heuristic) costs to the "goal" and the CostF are those two combined.
The index of the Field::Boxes vector is the number of the field, and every element contains the position.
My Heuristic function looks like this:
inline int Heuristic(Field &goal)
{
size_t d = 0;
for (size_t i = 0; i < Boxes.size(); i++)
{
d += (std::abs(static_cast<int>(Boxes[i].x) - static_cast<int>(goal.Boxes[i].x))
+ std::abs(static_cast<int>(Boxes[i].y) - static_cast<int>(goal.Boxes[i].y)));
}
return d;
}
For better readability and stuff, the code also is on Github. However, to execute it, you need SFML in your Visual Studio include direction.
Every help is appreciated!
Edit 1:
You now no longer need SFML to executed & debug the program! I commited the changes to github, the link is the same.
The problem is that although you remove the current node from your frontier, you never added it to the explored set, i.e. you never close it. The following code should work. My revisions closely follow Wikipedia's A* Pseudocode.
I also recommend you test your algorithm with the trivial heuristic (the one that returns zero for all values) on a simple puzzle to verify that your algorithm is implemented correctly. (See this answer for a brief explanation of this technique.)
while (!frontier.empty())
{
current = frontier.top();
frontier.pop();
if (++i > 500)
{
std::cout << "Iteration Error" << std::endl;
return searched;
}
// Check for goal here
if (Puzzle::finished(current)
{
std::cout << "Found goal!" << std::endl;
return MakePath(explored[current], start);
}
explored[current] = current; //close the current node
searched.push_back(current);
for (Direction d : Puzzle::Actions(current))
{
child = Puzzle::Action(d, current);
if (isIn(child,explored))
{
continue; //ignore the neighbor which is already evaluated
}
child.CostG = current.CostG + 1; // Make a step
if (!isIn(child, frontier)) //discovered a new node
{
frontier.push(child);
}
else if (child.CostG >= explored[child].CostG)
{
continue; //this is not a better path
{
//the path is best until now. Record it!
child.CostH = Puzzle::Heuristic(child, goal); // Calculate Heuristic
child.CostF = child.CostG + child.CostH; // Calculate final costs
//frontier.push(child); moved up to earlier point in code
explored[child] = child;
explored[child].setParent(&explored[current]);
}
}

Program returning blinking Cursor

So im doing a sort Method using the bubble sort and compareTo method
Yet for some reason, when I run the program it compiles, does no errors whatsoever and shows a blinking cursor in the program (as if u are about to type something in; which u can, just when u press enter nothing happens) and this cursor keeps blinking.
What's wrong here ? (code based on teacher's instructions)
public static void sort(ArrayList al)
{
Person p,p1,p2;
String a1,a2;
boolean flag = true;
System.out.println("Database will be sorted acc to ID ");
System.out.println();
do
{
flag = false;
for (int i=0;i<al.size()-1;i++)
{
p = (Person)al.get(i);
a1=((Person)al.get(i)).personID;
a2=((Person)al.get(i+1)).personID;
if (a1.compareTo(a2) > 0){
p1= (Person)al.get(i);
p2 =(Person)al.get(i+1);
}
}
}
while (flag = true);
if (flag = false)
{
for (int i = 0; i < al.size(); i++)
{
p = (Person) al.get(i);
System.out.println("----------" + (i+1) + "-----------");
System.out.println("ID Number: "+ p.personID);
System.out.println("Name: "+ p.name);
System.out.println("Day of Birth: " +p.dayDOB);
System.out.println("Month of Birth: " +p.monthDOB);
System.out.println("Year of Birth: " +p.yearDOB);
System.out.println("Telephone Number: " +p.telNum);
System.out.println("");
}
}
The problem is in this loop:
do
{
....
}
while (flag = true);
You want to compare flag to true, i.e. flag == true, but instead you set flag to true with flag = true. Therefore, the loop will not exit, but instead run forever (or until you terminate the program).
You have the same problem in the following if statement.

Synchronizing MapB to MapA in C++

I have a std::map that I generate from a json and a map that I generate from sqlite.
I want to compare the two maps and make changes to the sqlite so that it matches the json. I originally used the map.find(key) method through both maps to figure out what to add and what to delete but my friend told me that map was sorted from least to greatest key and so I could just run through it once.
I came up with two methods. Do you have any advice on which algorithm would be preferred and why? I am thinking the one I have uncommented is faster as (and please correct me if I'm wrong) I believe the uncommented one is O(n) worst case while the latter is O(n^2) worst case.
Also, my friend had mentioned that I didn't need the second 'clean up' while loop to reconcile the remaining sqlMap items, but I really think I need it. Is he right?
Here's my code:
void SqlSync::syncEvents() {
int added = 0;
int replaced = 0;
int deleted = 0;
int skipped = 0;
// get categories from Apsiva
std::map<int, Event> jsonMap = _apsivaRest->getEvents();
// get categories from sqlite
std::map<int, Event> sqlMap = _sqliteConnection->getEventMap(true);
// COMPARE
map<int, Event>::iterator jsonIter = jsonMap.begin();
map<int, Event>::iterator sqlIter = sqlMap.begin();
while (jsonIter != jsonMap.end() && sqlIter != sqlMap.end()) {
int jsonId = jsonIter->first;
Event jsonObj = jsonIter->second;
int sqlId = sqlIter->first;
if (jsonId < sqlId) {
// add
_sqliteConnection->addEvent(jsonObj);
++added;
++jsonIter;
} else if (jsonId > sqlId) {
// remove
_sqliteConnection->deleteEvent(sqlId);
++deleted;
++sqlIter;
} else {
if (jsonObj.isNewerThan(sqlIter->second)) {
_sqliteConnection->updateEvent(jsonObj);
++replaced;
} else {
// ignore
cout << "Skipped event b/c not newer" << endl; // delete when verified
++skipped;
}
++jsonIter;
++sqlIter;
}
}
// int jRemaining = std::distance(jsonIter, jsonMap.end());
// int sRemaining = std::distance(sqlIter, sqlMap.end());
// add remaining jsonMap Objects
while (jsonIter != jsonMap.end()) {
Event jsonObj = jsonIter->second;
_sqliteConnection->addEvent(jsonIter->second);
++added;
++jsonIter;
}
// delete remaining sqlMap Objects
while (sqlIter != sqlMap.end()) {
_sqliteConnection->deleteEvent(sqlIter->first);
++deleted;
++sqlIter;
}
// OLD WAY TO COMPARE.
// // add/replace keys found in json
// for (map<int, Event>::const_iterator jsonIter = jsonMap.begin(); jsonIter != jsonMap.end(); ++jsonIter) {
// map<int,Event>::const_iterator it = sqlMap.find(jsonIter->first);
// Event jsonObj = jsonIter->second;
// if (it != sqlMap.end()) {
// Event sqlObj = it->second;
// if (jsonObj.isNewerThan(sqlObj)) {
//// _sqliteConnection->updateEvent(jsonObj);
// ++replaced;
// } else {
// // ignore
// cout << "Skipped category b/c not newer" << endl; // delete when verified
// ++skipped;
// }
// } else {
//// _sqliteConnection->addEvent(jsonObj);
// ++added;
// }
// }
//
// // delete sqlmap CategoryRows not in jsonMap
// for (map<int, Event>::const_iterator sqlObj = sqlMap.begin(); sqlObj != sqlMap.end(); ++sqlObj) {
// if (jsonMap.find(sqlObj->first) == jsonMap.end()) {
//// _sqliteConnection->deleteEvent(sqlObj->first);
// ++deleted;
// }
// }
#ifdef DEBUG
cout << "CATEGORIES SYNC:" << endl;
cout << "---------------" << endl;
cout << "Added: " << added << " | Replaced: " << replaced
<< " | Deleted: " << deleted << " | Skipped: " << skipped << endl;
#endif //DEBUG
}
The uncommented way is more efficient. The complexity will be O(n+m) when n and m are sizes of json and SQLite maps.
You will need the last loop, since when you exit the first loop you don't know which map end you reached first. Consider next case - json map has ids 1,2,4,5 and SQLite has ids 1,2,6,7.
You will need the last loop in order to delete items 6 and 7.

Nested for loop being ignored after if-else chain

I am programming a MARIE assembler for one of my classes and I've ran into a logical error involving my control structure for one of my functions.
What I'm trying to accomplish is taking in all the data that was inserted into my vectors and then that data is being used to create integer opcode data for display. Yet for whatever reason my nested for loop is being ignored after my if-else chain.
The code within the nested for-loop seems to be working properly aside from this one logic error.
Please note that instructions, hexNums, secondPassData, valueZ, and symBols are my vectors.
For some clarification:
The If-Else chain is just used to read instruction words and to set basedInt to the proper decimal number for later hexadecimal conversion.
There are a few special conditions in the code below which are marked.
If there is no special condition then the code checks the valueZ vector at instructions.at(i) to see if the valueZ element is in symBols.
If it is a symBol element through character checks, it takes its hexNums position and adds it to the basedInt.
If it is not, it instead has its corresponding valueZ element converted from string to int and then added to the basedInt.
Those elements are added to the secondPassData vector.
int basedInt;
int newInt;
int pushInt;
string temp;
for(unsigned int i = 0; i < instructions.size(); ++i) //if i is less then instructions.size(), follow through with the statement
{
if(instructions.at(i) == "JNS") //sets basedInt to a decimal version of its hexidecimal opcode
{
basedInt = 0;
}
else if(instructions.at(i) == "HALT") //a special condition where the number is plugged into the secondPassData vector automatically
{
secondPassData.push_back(28672);
continue;
}
else if(instructions.at(i) == "CLEAR") //same as above
{
secondPassData.push_back(-24576);
continue;
}
else if(instructions.at(i) == "ADDL")
else if(instructions.at(i) == "ORG")
{
secondPassData.push_back(0000);
continue;
}
else if(instructions.at(i) == "HEX") //checks for the HEX psuedo-OP.
{
temp = valueZ.at(i); //converts it at position i to a string
basedInt = atoi(temp.c_str()); //converts that string to an int.
secondPassData.push_back(basedInt);//pushes into vector.
continue;
}
else if(instructions.at(i) == "DEC")
{
temp = valueZ.at(i);
basedInt = atoi(temp.c_str()); //similar function as above.
secondPassData.push_back(basedInt);
continue;
}
else
{
cout << "Beep Boop, program borked!" << endl;
return;
}
//for some reason the code below is getting ignored.
cout << i << endl;
for(unsigned int a = 0; a < instructions.size(); ++a) //works
{
cout << i << " " << a << endl;
string valFind = valueZ.at(i);
string symFind = symBols.at(a); //works
temp = valueZ.at(i);
if(symFind[0] == valFind[0])
{
newInt = hexNums.at(a);
pushInt = basedInt + newInt;
secondPassData.push_back(pushInt);
break;
}
else if(symFind[0] != valFind[0]) //works
{
temp = valueZ.at(i);
newInt = atoi(temp.c_str()); //works
pushInt= basedInt + newInt;
secondPassData.push_back(pushInt); //works
break;
}
break;
}
}
If you hit a continue in your else-if chain your main for loop will jump to its next iteration and will skip the rest of your code (in this case your nested for loop)
continue