QT scene->removeItem (* QgraphicsItem) removes the object from the scene but it is still observed - c++

I am creating a simple game using QT c ++, I have an asteroid class and a Qvector of said class. Every 15 seconds an asteroid is created and added to the Qvector.
void MainWindow::generarAsteroides(){
srand(time(NULL));
int aleatorio=1+rand()%1000;
int a_w = 30+rand()%200;
v_asteroides.push_back(new asteroides(aleatorio,-1000,a_w,a_w,500));
mundo->addItem(v_asteroides.last());
std::cout << "Asteroide generado en X : "<< aleatorio << std::endl;
sonido->stop();
sonido->setMedia(QUrl("qrc:/multimedia/suspenso1.mp3"));
sonido->play();
}
when it exceeds a certain Y coordinate, I call a function through a Timer to traverse the vector and eliminate from the scene with
void MainWindow::actualizar(){
for(auto &ast : v_asteroides){
if(ast->destruir()){
mundo->removeItem(ast);
v_asteroides.erase(std::remove(v_asteroides.begin(),v_asteroides.end(),ast),v_asteroides.end());
sonido->stop();
sonido->setMedia(QUrl("qrc:/multimedia/explosion1.mp3"));
sonido->play();
//std::cout << "eliminado" <<std::endl;
}
}
//std::cout << "tamaƱo : " <<v_asteroides.size() << std::endl;
mundo->advance();
mundo->update();}
however the object that is supposed to be removed from the screen remains there (still) without disappearing.

The error is that : for (xx : vs_) and vs_.erase can not be used together.
You should use the iter returned by v_asteroides.erase(xxx) for the next loop.
use next code as suggested:
auto iter = vs_.begin();
for (; iter != vs_.end(); )
{
//if need erase
{
//other logic code
// mundo->removeItem(*iter);
iter = vs_.erase(iter); // at last row
}
// else
{
//++iter;
}
}

Related

How can I add different names to a vector using classes?

#include <iostream>
#include <string>
#include <vector>
class Enemy
{
private:
std::string rank = "Boss";
std::string rank2 = "Miniboss";
public:
std::string type;
std::string get_rank(){
return rank;
}
std::string get_rank2(){
return rank2;
}
};
int add_enemy(std::vector<Enemy>&enemies, Enemy enemy) // I wanna pass by reference because I want to modify the vector
{
for(size_t i; i < enemies.size(); i++) {
if(enemies.at(i).type == enemy.type){ // here I'm saying, if I add an enemy that's of the same type, I don't wanna add it anymore
return 1; // it returns an error, because they are the same type, so it shouldn't add it?
}
}
enemies.push_back(enemy);
}
int main()
{
Enemy enemy;
enemy.type = "Dragon";
std::cout << enemy.type << " is a " << enemy.get_rank() << std::endl;
Enemy nrone, nrtwo, nrthree, nrfour, nrfive;
// I want to add these and keep them in a vector
std::vector<Enemy> enemies;
nrone.type = "Orc";
nrtwo.type = "Goblin";
nrthree.type = "Troll";
nrfour.type = "Ogre";
nrfive.type = "Orc";
std::cout << nrfour.type << " is of rank " << nrfour.get_rank2() << std::endl;
enemies.push_back(nrone);
enemies.push_back(nrtwo);
enemies.push_back(nrthree);
enemies.push_back(nrfour);
enemies.push_back(nrfive);
std::cout << add_enemy(enemies, enemy) << std::endl;
return 0;
}
Hi, I am studying Classes & Objects in C++ right now, and I'm trying to achieve the following: create a vector of NPC monsters and add a bunch of monster types to the vector. However, if the monster/enemy is of the same type, I don't want to add it to the vector, but discard it.
In my case, I have two Orcs, so the vector should discard one of the orcs, but it doesn't, and instead if showing me a strange number on the screen.
I tried it this way and I still can't figure it out :( Any solutions?
So the reason that both Orcs are added is because by the time you run add_enemy, you've already added them. All the enemies should be using the add_enemy function instead of push_back:
int main()
{
Enemy enemy;
enemy.type = "Dragon";
std::cout << enemy.type << " is a " << enemy.get_rank() << std::endl;
Enemy nrone, nrtwo, nrthree, nrfour, nrfive;
// I want to add these and keep them in a vector
std::vector<Enemy> enemies;
nrone.type = "Orc";
nrtwo.type = "Goblin";
nrthree.type = "Troll";
nrfour.type = "Ogre";
nrfive.type = "Orc";
std::cout << nrfour.type << " is of rank " << nrfour.get_rank2() << std::endl;
enemies.push_back(nrone); //Add one Orc
enemies.push_back(nrtwo);
enemies.push_back(nrthree);
enemies.push_back(nrfour);
enemies.push_back(nrfive); //Add another Orc
std::cout << add_enemy(enemies, enemy) << std::endl; //The Orcs are already in enemies!
return 0;
}
The reason you're seeing a strange number on the screen is that if you DO successfully add an enemy, the function doesn't return anything:
int add_enemy(std::vector<Enemy>&enemies, Enemy enemy) // I wanna pass by reference because I want to modify the vector
{
for(size_t i; i < enemies.size(); i++) {
if(enemies.at(i).type == enemy.type){
return 1; // Return an error
}
}
enemies.push_back(enemy); //OK, so we added the enemy, but where's the return?
}
Your add_enemies function must return a value, since it is declared as type int.
P.S... consider using a range based loop to make things a little easier:
for(Enemy& existingEnemy: enemies) {
if(enemy.type == existingEnemy.type) {
return 1;
}
}
The main problem is that you are not initializing the loop variable (i) in your add_enemy function (so the loop may never run, or it may skip some elements). Also, that function must return a value (presumably, 0) if the loop ends.
Try this:
int add_enemy(std::vector<Enemy>& enemies, Enemy enemy) // I wanna pass by reference because I want to modify the vector
{
for (size_t i = 0; i < enemies.size(); i++) { /// You forgot to initialize "i"!
if (enemies.at(i).type == enemy.type) { // here I'm saying, if I add an enemy that's of the same type, I don't wanna add it anymore
return 1; // it returns an error, because they are the same type, so it shouldn't add it?
}
}
enemies.push_back(enemy);
return 0; // The function MUST return an int value!
}
The strange number is easily explained. In your function you fail to return anything in the case where you do add the enemy. Add a return value and the strange number will go away.
int add_enemy(std::vector<Enemy>&enemies, Enemy enemy)
{
for(size_t i = 0; i < enemies.size(); i++) {
if(enemies.at(i).type == enemy.type){
return 1;
}
}
enemies.push_back(enemy);
return 0; // added a return value
}
The second problem with two orcs is also easily explained. You didn't use your add_enemy function when you added the orcs, you just used the regular vector push_back method so both orcs got added to the vector. You only used your add_enemy method for the dragon.
Also you fail to initialise i in the loop. I didn't spot that but I've corrected the code above.

Segmentation Fault encountered while implementation of DFS using STL in C++

Debugging of segmentation fault is one of the key issues I am facing as beginner in C++. I had tried to implement Depth First Search in Directed Graphs using C++ STL in the following lines of code (based on Steven Skienna's Algorithm Design Manual) :
#include <iostream>
#include <list>
#include <cstdio>
using namespace std;
#define TREE 0 /* tree edge */
#define BACK 1 /* back edge */
#define CROSS 2 /* cross edge */
#define FORWARD 3 /* forward edge */
class Graph
{
int V; //no of vertices
int time;
list <int> *adj; //Pointer to an array containeing the adjacency list
public:
Graph(int V); //A constructor
int entry_time[] ,exit_time[] , parent[] ;
bool processed[] , discovered[] ;
void addEdge(int v , int w ) ; // a function to add an edge to graph
void DFS(int v); // print DFS transversal of the complete graph
void initializeGraph () ; // a function used by DFS
void process_edge(int x , int y);
void process_vertex_early(int x);
void process_vertex_late(int x);
int edge_classification(int x , int y);
};
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V]; // dynamic allocation of V lists to an array named adj
}
void Graph::addEdge(int v, int w )
{
adj[v].push_back(w); //Add w to v's list
}
void Graph::initializeGraph ()
{
time = 0;
for (int j=0;j<V;j++)
{
processed[j]=discovered[j] = false;
parent[j]=-1;
}
// Recur for all the vertices adjacent to this vertex
}
void Graph::DFS(int v)
{
process_vertex_early(v);
list <int>::iterator i ;
for (i=(adj[v].begin());i!=adj[v].end();++i)
{ cout << *i ;
if (discovered[*i]==false)
{
parent[*i] = v ;
process_edge(v,*i);
DFS(*i);
}
else if (processed[*i]==false)
process_edge(v,*i);
}
process_vertex_late(v);
}
void Graph::process_vertex_early(int v)
{
discovered[v] = true;
time = time +1 ;
entry_time[v] = time ;
printf("discovered vertex %d at time %d\n",v, entry_time[v]);
}
void Graph::process_vertex_late(int v)
{
time = time + 1 ;
exit_time[v] = time;
processed[v] = true;
//printf("processed vertex %d at time %d\n",v, exit_time[v]);
}
int Graph::edge_classification (int x , int y )
{
if (parent[y]==x) return (TREE);
if (discovered[y] && !processed[y]) return (BACK);
//cout << " Warning : self loop " << x << y ;
}
void Graph::process_edge(int x , int y)
{
int type ;
type = edge_classification(x,y);
//if (type== BACK) cout << "Back Edge" << x << " -> " << y << endl;
//else if (type== TREE) cout << "Tree Edge" << x << " -> " << y << endl;
//else cout << " Not in the type " ;
}
int main()
{
Graph g(4);
g.initializeGraph();
g.addEdge(0,1);
g.addEdge(0,2);
g.addEdge(1,2);
g.addEdge(2,0);
g.addEdge(2,3);
g.addEdge(3,1);
cout << " Following is a DFS transversal \n " ;
g.DFS(0);
return 0;
}
Segmentation Fault occurs after the search operation reaches a depth of one or two. I had tried applying Breadth First Search using a similar syntax which worked . Please help me in debugging this code . Thanks .
Step one is to read all compiler warnings (and compile with warnings switched on).
For example:
int entry_time[] ,exit_time[] , parent[] ;
These arrays are defined with no size - but you are putting data in them. This means you are writing outside the array boundaries which cause Undefined Behavior (such as the crashing and double-frees you are seeing). Either allocate space for these arrays like you do for adj, or use another container (such as vector) which you can resize as needed.
Also edge_classification doesn't always return a value - your compiler should have warned you about this.
Edit: More about std::vector
You can't declare your arrays to be as entry_time[V] because the value of V isn't known at compile time. You could have many different Graph objects with different sizes.
If you change your arrays to std::vector you can then allocate their size in the Graph constructor and let the std::vector class worry about allocating and freeing memory.
For example:
In the class declare entry_time as a std:vector:
std::vector<int> entry_time;
In the constructor, set the size of the entry_time vector.
entry_time.resize(V);
Note that you can use V here as a parameter to resize as this is at run-time so it now has a value.
std::vector has a normal array-like accessor, so you can assign values into the entries of the vector as you would an array. For example, your existing code will still work:
entry_time[v] = time ;

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]);
}
}

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.

Lua_hook and lua_Debug->event

I'm trying to learn lua and building a virtual machine in c++, I want to write a debugging class, to make my life easier. I'm actually blocked because I don't understand how the callbacks are done, here is my code :
//Im here adding my fct to a global map.
void Debugger::setFctHook(void)
{
g_hookers[LUA_MASKCALL] = HookCall;
g_hookers[LUA_MASKRET] = HookRet;
g_hookers[LUA_HOOKTAILRET] = HookRet;
g_hookers[LUA_MASKLINE] = HookLine;
g_hookers[LUA_MASKCOUNT] = HookCount;
}
Here is my constructor :
Debugger::Debugger(VirtualMachine &vm, uint count)
: VM_(vm), count_(count)
{
setFctHook();
if (vm.isFonctionnal())
{
vm.addDebugger(this);
lua_sethook(vm.getLua(), HookEvents, 0, count_);
}
}
and my setter :
void Debugger ::setHook(int hookMask) const
{
std::cout << hookMask << "SETHOOOOOOOOOK" << std::endl;
lua_sethook(VM_.getLua(), HookEvents, hookMask, count_);
}
Here is my Central hook :
static void HookEvents(lua_State *lua, lua_Debug *debug)
{
std::map<int, fctHook>::iterator it;
std::cout << debug->event << std::endl;
it = g_hookers.find(debug->event);
if (it != g_hookers.end())
{
std::cout << "First: " << it->first << std::endl;
it->second(lua);
}
}
The problem is that the value show in my setter differs from the value printed in my central function hook, I tried many defines and I dont see any logic in the different values.
Result :
8 SETHOOOOOOOOOK // received on my setter.
3 // received on my central hook
I solved my problem, the problem is that my map has bad values on it, the correct defines for the hooks are :
void Debugger::setFctHook(void)
{
g_hookers[LUA_HOOKCALL] = HookCall;
g_hookers[LUA_HOOKRET] = HookRet;
g_hookers[LUA_HOOKTAILRET] = HookRet;
g_hookers[LUA_HOOKLINE] = HookLine;
g_hookers[LUA_HOOKCOUNT] = HookCount;
}