Bei Zuweisung entsteht Fehler



  • Hallo Leute,

    ich brauche (mal wieder 😞 ) eure Hilfe!

    Diesmal habe ich es geschafft, einen Fehler zu "erzeugen", den ich mir auf keine Weise erklären kann und an dem ich schon seit ein paar Stunden verzweifel... 😕

    Damit ihr grob wisst worum es geht: Ich bin dabei, mein eigenes "Tower Defense" Spiel zu erstellen, habe zwar schon einige Erfahrungen in C++, in der Spieleprogrammierung allerdings noch nicht.
    Dabei müssen die Gegner einen Weg zum Ziel finden. Dafür dachte ich mir, könnte man super den A*-Algorithmus verwenden, also habe ich den gesucht, gefunden, implementiert. So weit so gut.

    Aber dann tauchte dieser Fehler auf:
    Die Funktion in der der A*-Algorithmus ist (pathFind) benötigt einen

    int[20][20]
    

    . Dieses Array ist global deklariert, sodass ich aus allen Klassen problemlos drauf zu greifen kann (ich weiß, ist nicht optimal, aber erstmal soll das Spiel funktionieren, dann optimiere ich den Code 😉 )
    Leider, warum auch immer, ist dieses Array wenn pathFind aufgerufen wird, immer leer, obwohl ich es vorher mit Werten gefüllt habe:

    for(int y = 0; y < 20; ++y)
    	{
    		for(int x = 0; x < 20; ++x)
    		{
    			if(b->getValue(Point(x, y)) == FS_FREE || b->getValue(Point(x, y)) == FS_ENEMY)
    			{
    				aStar::map[x][y] = 0;
    			}
    			else
    			{
    				aStar::map[x][y] = 1;
    			}
    		}
    	}
    

    Nachdem ich verschiedenste Möglichkeiten ausprobiert habe, habe ich festgestellt, dass die Daten "vorhanden" bleiben, wenn ich das Array in einer Klasse als Member habe.
    Versuchte ich allerdings auf das Array aus der Funktion pathFind heraus zuzugreifen, so stürzte das Programm mit der Meldung ab, es sein ein Fehler aufgetreten. Eine Fehlermeldung kam leider nicht...

    Meine nächste Idee war, weil ich komischerweise in pathFind die Daten mittels einer MessageBox ausgeben konnte, die Daten des Arrays aus der Klasse in das globale Array zu kopieren.

    for(int i = 0; i < 20; ++i)
    	    	for(int j = 0; j < 20; ++j)
    	    		map[j][i] = Cursor::c->map.at(j).at(i);
    

    Wieder stürzte das Programm ohne Fehlermeldung ab.

    Ich hoffe ihr könnt mir helfen. Ich habe leider gar keine Idee, wo da ein Fehler auftreten könnte...



  • Was soll "das Array ist leer " bedeuten?



  • Oh 'schuldigung, ist ein bisschen schlecht formuliert.

    Ich meine damit, dass alle Werte im Array den Wert 0 haben (was für das Feld "leer" bedeutet).



  • Wird überhaupt jemals eine 1 reingeschrieben? Gibt es noch andere Werte neben FS_FREE und FS_ENEMY?

    Wie und wo ist das Array definiert/deklariert?



  • Die Frage habe ich mir auch schon gestellt. Tatsächlich wird das Array korrekt befüllt, also auch mit 1.
    Wird findPath aufgerufen, werden komischerweise alle Werte zu 0



  • Das ist dann der Punkt, an dem man den Debugger anwirft und so Schritt für Schritt nachvollzieht, wo das array derartig umgeschrieben wird.



  • Der Ansatz "erst funktionieren und dann schön machen" ist übrigens sehr schlecht.

    Das solltest du dir Imho erst gar nicht angewöhnen.



  • cvcv schrieb:

    Der Ansatz "erst funktionieren und dann schön machen" ist übrigens sehr schlecht.

    Das solltest du dir Imho erst gar nicht angewöhnen.

    👍 Kenne das aus eigener Erfahrung. Wenn es dann erst mal funktioniert, fasst man die betroffenen schlechten Stellen nicht noch mal an.



  • cvcv schrieb:

    Der Ansatz "erst funktionieren und dann schön machen" ist übrigens sehr schlecht.

    Das solltest du dir Imho erst gar nicht angewöhnen.

    War auch nicht so gemeint, dass ich einfach drauf los schreibe und hoffe das es funktioniert und dann etwas aufräume. Lediglich wenn ein Problem auftritt, suche ich erst nach einer Lösung, und versuche erst dann, diese schön zu integrieren. 😉

    So, hab es nun geschafft, das in dem Array map alle Werte richtig gespeichert sind.

    Ein Problem gelöst = Ein neues taucht auf (zumindest oft 😃 )

    Der Fehler muss diesmal im A* Algorithmus liegen, den ich zugegebener Weise nicht selbst geschrieben habe. Und zwar "laufen" die Enemies trotz Mauern direkt zum Ziel und das Programm stürzt ab, wenn einer von ihnen "auf" einer Mauer steht. Leider umlaufen sie diese gar nicht.

    std::string pathFind(const int & xStart, const int & yStart, const int & xFinish, const int & yFinish)
    	{
    	    static std::priority_queue<node> pq[2]; // list of open (not-yet-tried) nodes
    	    static int pqi; // pq index
    	    static node* n0;
    	    static node* m0;
    	    static int i, j, x, y, xdx, ydy;
    	    static char c;
    	    pqi=0;
    	    //memcpy(map, Board::Map, sizeof(int) * 400);
    	    std::string s("");
    
    	    for(int i = 0; i < 20; ++i)
    	    {
    	    	for(int j = 0; j < 20; ++j)
    	    		map[j][i] = Cursor::c->map.at(j).at(i);
    	    	s += "";
    	    }
    	    for(int i = 0; i < 20; ++i)
    	    {
    	    	for(int j = 0; j < 20; ++j)
    	    		s += std::to_string(map[j][i]);
    	    	s += "\n";
    	    }
    
    	    MessageBox(NULL, s.c_str(), "map", 0);
    	    // reset the node maps
    	    for(y=0;y<m;y++)
    	    {
    	        for(x=0;x<n;x++)
    	        {
    	            closed_nodes_map[x][y]=0;
    	            open_nodes_map[x][y]=0;
    	        }
    	    }
    
    	    // create the start node and push into list of open nodes
    	    n0=new node(xStart, yStart, 0, 0);
    	    n0->updatePriority(xFinish, yFinish);
    	    pq[pqi].push(*n0);
    	    open_nodes_map[x][y]=n0->getPriority(); // mark it on the open nodes map
    
    	    // A* search
    	    while(!pq[pqi].empty())
    	    {
    	        // get the current node w/ the highest priority
    	        // from the list of open nodes
    	        n0=new node( pq[pqi].top().getxPos(), pq[pqi].top().getyPos(), 
    	                     pq[pqi].top().getLevel(), pq[pqi].top().getPriority());
    
    	        x=n0->getxPos(); y=n0->getyPos();
    
    	        pq[pqi].pop(); // remove the node from the open list
    	        open_nodes_map[x][y]=0;
    	        // mark it on the closed nodes map
    	        closed_nodes_map[x][y]=1;
    
    	        // quit searching when the goal state is reached
    	        //if((*n0).estimate(xFinish, yFinish) == 0)
    	        if(x==xFinish && y==yFinish) 
    	        {
    	            // generate the path from finish to start
    	            // by following the directions
    	            std::string path="";
    	            while(!(x==xStart && y==yStart))
    	            {
    	                j=dir_map[x][y];
    	                c='0'+(j+dir/2)%dir;
    	                path=c+path;
    	                x+=dx[j];
    	                y+=dy[j];
    	            }
    
    	            // garbage collection
    	            delete n0;
    	            // empty the leftover nodes
    	            while(!pq[pqi].empty()) pq[pqi].pop();           
    	            return path;
    	        }
    
    	        // generate moves (child nodes) in all possible directions
    	        for(i=0;i<4;i++)
    	        {
    	            xdx=x+dx[i]; 
    				ydy=y+dy[i];
    
    	            if(!(xdx<0 || xdx>n-1 || ydy<0 || ydy>m-1 || map[xdx][ydy] == 1 || closed_nodes_map[xdx][ydy]==1))
    	            {
    	                // generate a child node
    	                m0=new node( xdx, ydy, n0->getLevel(), n0->getPriority());
    	                m0->nextLevel(i);
    	                m0->updatePriority(xFinish, yFinish);
    
    	                // if it is not in the open list then add into that
    	                if(open_nodes_map[xdx][ydy]==0)
    	                {
    	                    open_nodes_map[xdx][ydy]=m0->getPriority();
    	                    pq[pqi].push(*m0);
    	                    // mark its parent node direction
    	                    dir_map[xdx][ydy]=(i+dir/2)%dir;
    	                }
    	                else if(open_nodes_map[xdx][ydy]>m0->getPriority())
    	                {
    	                    // update the priority info
    	                    open_nodes_map[xdx][ydy]=m0->getPriority();
    	                    // update the parent direction info
    	                    dir_map[xdx][ydy]=(i+dir/2)%dir;
    
    	                    // replace the node
    	                    // by emptying one pq to the other one
    	                    // except the node to be replaced will be ignored
    	                    // and the new node will be pushed in instead
    	                    while(!(pq[pqi].top().getxPos()==xdx && pq[pqi].top().getyPos()==ydy))
    	                    {                
    	                        pq[1-pqi].push(pq[pqi].top());
    	                        pq[pqi].pop();       
    	                    }
    	                    pq[pqi].pop(); // remove the wanted node
    
    	                    // empty the larger size pq to the smaller one
    	                    if(pq[pqi].size()>pq[1-pqi].size()) pqi=1-pqi;
    	                    while(!pq[pqi].empty())
    	                    {                
    	                        pq[1-pqi].push(pq[pqi].top());
    	                        pq[pqi].pop();       
    	                    }
    	                    pqi=1-pqi;
    	                    pq[pqi].push(*m0); // add the better node instead
    	                }
    	                else delete m0; // garbage collection
    		        }
    	        }
    	        delete n0; // garbage collection
    	    }
    	    return ""; // no route found
    	}
    

    Freue mich weiterhin über eure Hilfe! Ihr seid echt klasse! (muss man auch mal sagen) 😃 👍



  • cvcv schrieb:

    Der Ansatz "erst funktionieren und dann schön machen" ist übrigens sehr schlecht.

    hm... Test Driven Development funktioniert doch genau nach diesem Muster... Stichwörter "Red-green-refactor"



  • daddy_felix schrieb:

    cvcv schrieb:

    Der Ansatz "erst funktionieren und dann schön machen" ist übrigens sehr schlecht.

    hm... Test Driven Development funktioniert doch genau nach diesem Muster... Stichwörter "Red-green-refactor"

    Mag sein, fand ich aber auch nie gut.

    Was soll das für ein Sinn haben etwas erst irgendwie 0815 reinzuschludern um es dann schön zu machen?

    Wenn die Spezifikationen passen dann entwickelt man schon was gefordert ist - und wenn sie nicht passen, dann wird auch mein selbst geschriebener Test nicht helfen.

    Und auch da dreht es sich um kleine Dinge.
    Klar kann man mal ein paar Zeilen Code erst mal unsauber reinschreiben ukd schauen ob das Ergebnis wie gedacht ist und es danach dann sauber implementieren - aber das sollte man nicht mit 300 Zeilen Code machen.

    @Thema:

    Sorry aber da bin ich raus. Debug es oder minimalbeispiel.



  • Such dir eine bessere Implementierung des A*-Algorithmus. Dieser benutzt unnötige Heap-Allokationen und ist viel zu kompliziert.
    Schau mal unter Implementation of A* - A* Search.


Anmelden zum Antworten