Aktuelle Array Position



  • Wow! Perfekt! Vielen Dank!

    Noch einige Sachen die ich zu ändern habe, aber das versuche ich erstmal selber zu lösen 🙂



  • Belli schrieb:

    Wie sorgst Du denn eigentlich dafür, dass nicht alle untereinander stehenden Bäume sofort anfangen zu brennen?

    Wenn ich mir vorstelle, dass in Spalte 15 i Bäume übereinander stehen, und der in Zeile 0 brennt, dann zündest Du bei i=0 den darunter an, und wenn Du die nächste Zeile durchgehst, erkennst Du nicht mehr, ob der Baum [1][15] schon vorher gebrannt hat, oder ob Du ihn gerade erst angezündet hast, also zündest Du jetzt [2][15] an, und so weiter, oder sehe ich das falsch?

    Durch den Zähler "c" den ich aus dem Hauptprogramm ausgebe werden nur eine eingestelle Anzahl an Durchgängen durchgeführt. Aber das klappt alles sowieso noch nicht so wie ich wollte. Ich konnte aber nicht weiter machen, da mit die Arrays Kopfzerbrechen gebrahct haben



  • Da mir die Schleife echt Probleme mit einem sauberen abbrennen macht, wäre es gut wenn ich das array irgendwie durchsuchen könnte und gleichzeitig alle Werte die zb '+' sind bearbeiten kann.

    Ich hab zb das Problem das die Schleife zückwerts nicht mehr prüft ob da was brennt.



  • Siehe Floodfill. Bei einem Waldbrand kannst du den Algorithmus auch leicht steuern, dass die Windrichtung einbezogen wird (scharfer Wind aus Nord-Ost-> nur linke und untere Bäume fangen jeweils Feuer).
    Und schau dir gleich die iterative Lösung an, ein std::vector<Point> bietet sich als Stack an.
    Du nimmst also die zu überprüfende Position vom stack und überprüfst die entsprechenden Richtungen, bei einem Treffer markierst du die Position als abgebrannt und fügst die Koordinate dem Stack hinzu.

    Das machst du dann so lange, bis der Stack leer ist.



  • yahendrik schrieb:

    ein std::vector<Point> bietet sich als Stack an.

    Aua. nimm doch lieber einen std::stack<Point> als Stack 😃



  • b4mbus schrieb:

    Belli schrieb:

    Wie sorgst Du denn eigentlich dafür, dass nicht alle untereinander stehenden Bäume sofort anfangen zu brennen?

    Wenn ich mir vorstelle, dass in Spalte 15 i Bäume übereinander stehen, und der in Zeile 0 brennt, dann zündest Du bei i=0 den darunter an, und wenn Du die nächste Zeile durchgehst, erkennst Du nicht mehr, ob der Baum [1][15] schon vorher gebrannt hat, oder ob Du ihn gerade erst angezündet hast, also zündest Du jetzt [2][15] an, und so weiter, oder sehe ich das falsch?

    Durch den Zähler "c" den ich aus dem Hauptprogramm ausgebe werden nur eine eingestelle Anzahl an Durchgängen durchgeführt. Aber das klappt alles sowieso noch nicht so wie ich wollte. Ich konnte aber nicht weiter machen, da mit die Arrays Kopfzerbrechen gebrahct haben

    Ich würde es folgendermaßen machen:
    Das Array zweimal vorhalten.
    In einer Version ist der aktuelle Zustand.
    Dieses Array durchsuchen nach den Änderungen, die zu machen sind.
    Die Änderungen aber machst Du in der anderen Version des Arrays.
    Dadurch ist sichergestellt, dass sich die Änderungen eines Laufes nicht unerwünscht auswirken.
    Wenn Du damit fertig bist, gibst Du das geänderte Array aus.
    Beim nächsten Durchlauf tauschen die beiden Arrays die Rollen, dh. das heißt, nun durchsuchst Du das Array, das im vorigen Durchlauf geändert worden ist, baust das andere Array, das zuvor durchsucht worden ist, wieder neu auf.

    Ein Array ist also jeweils Quelle, eins Ziel, und nach jedem Durchlauf tauschen sie diese Rolle.



  • yahendrik schrieb:

    Siehe Floodfill. Bei einem Waldbrand kannst du den Algorithmus auch leicht steuern, dass die Windrichtung einbezogen wird (scharfer Wind aus Nord-Ost-> nur linke und untere Bäume fangen jeweils Feuer).
    Und schau dir gleich die iterative Lösung an, ein std::vector<Point> bietet sich als Stack an.
    Du nimmst also die zu überprüfende Position vom stack und überprüfst die entsprechenden Richtungen, bei einem Treffer markierst du die Position als abgebrannt und fügst die Koordinate dem Stack hinzu.

    Das machst du dann so lange, bis der Stack leer ist.

    lol?

    Kapsel deinen Wald in ´ne Klasse oder Struktur und erzeuge aus deinem Anfangswald den Folgewald. Dazu ein paar Zugriffsfunktionen und fertig.

    Konnte jetzt nicht widerstehen 😞

    #include <vector>
    #include <iostream>
    
    namespace TreeState
    {
    	enum State_t
    	{
    		Invalid,
    		Whole,
    		Lit,
    		Burnt
    	};
    }
    
    class Forest
    {
    	std::size_t ExtentX_;
    	std::size_t ExtentY_;
    
    	std::vector<TreeState::State_t> TreeStates_;
    
    public:
    	Forest() :
    		Forest( 30, 30 )
    	{
    	}
    
    	Forest( std::size_t EX, std::size_t EY ) :
    		ExtentX_( EX ),
    		ExtentY_( EY ),
    		TreeStates_( EX * EY, TreeState::Whole )
    	{
    	}
    
    	std::size_t extent_x() const
    	{
    		return ExtentX_;
    	}
    
    	std::size_t extent_y() const
    	{
    		return ExtentY_;
    	}
    
    	TreeState::State_t tree_state( std::size_t x, std::size_t y ) const
    	{
    		if( x < extent_x() && y < extent_y() )
    		{
    			return TreeStates_[make_index( x,y )];
    		}
    		return TreeState::Invalid;
    	}
    
    	void set_tree_state( std::size_t x, std::size_t y, TreeState::State_t State )
    	{
    		if( x < extent_x() && y < extent_y() )
    		{
    			TreeStates_[make_index( x,y )] = State;
    		}
    	}
    
    private:
    	std::size_t make_index( std::size_t x, std::size_t y ) const
    	{
    		return extent_x() * y + x;
    	}
    };
    
    char tree_state_symbol( TreeState::State_t State )
    {
    	if( State == TreeState::Whole )        return 'X';
    	else if( State == TreeState::Lit )     return '+';
    	else if( State == TreeState::Burnt )   return '-';
    	else                                   return '?';
    }
    
    std::ostream& operator<<( std::ostream& os, const Forest& f )
    {
    	for( size_t y = 0; y < f.extent_y(); ++y )
    	{
    		for( size_t x = 0; x < f.extent_x(); ++x )
    		{
    			os << tree_state_symbol( f.tree_state( x,y ) );
    		}
    		os << "\n";
    	}
    	return os;
    }
    
    Forest spread_ignition( const Forest& f )
    {
    	Forest retVal( f.extent_x(), f.extent_y() );
    	for( size_t y = 0; y < f.extent_y(); ++y )
    	{
    		for( size_t x = 0; x < f.extent_x(); ++x )
    		{
    			if( f.tree_state( x,y ) == TreeState::Whole )
    			{
    				if( f.tree_state( x -1, y ) == TreeState::Lit ||
    					f.tree_state( x +1, y ) == TreeState::Lit ||
    					f.tree_state( x, y -1 ) == TreeState::Lit ||
    					f.tree_state( x, y +1 ) == TreeState::Lit )
    				{
    					// heil -> brennend
    					retVal.set_tree_state( x, y, TreeState::Lit );
    				}
    			}
    			else if( f.tree_state( x,y ) == TreeState::Lit )
    			{
    				// brennend -> verbrannt
    				retVal.set_tree_state( x, y, TreeState::Burnt );
    			}
    			else
    			{
    				// verbrannt bleibt verbrannt
    				retVal.set_tree_state( x, y, f.tree_state( x,y ) );
    			}
    		}
    	}
    	return retVal;
    }
    
    int main()
    {
    	Forest f( 9, 5 );
    	f.set_tree_state( 4, 2, TreeState::Lit );
    
    	std::cout << f << "\n\n";
    
    	f = spread_ignition( f );
    	std::cout << f << "\n\n";
    
    	f = spread_ignition( f );
    	std::cout << f << "\n\n";
    
    	f = spread_ignition( f );
    	std::cout << f << "\n\n";
    }
    

    Edit:
    Funktionsaufrufe korrigiert.

    Edit 2:
    Programm korrigiert. Bis auf Weiteres 🙄



  • 1. Wie lange brennt denn ein Baum eigentlich? Abgebrannte Bäume kommen bei DocShoe nicht vor, wenn ich das richtig sehe. Will die Aufgabe vielleicht, dass nach einer Runde brennen ein Baum abgebrannt ist?

    2. Was tut ignition_progress? Refactoring/Umbenennung in spread_ignition, ohne alle Vorkommen zu ersetzen?



  • wob schrieb:

    2. Was tut ignition_progress? Refactoring/Umbenennung in spread_ignition, ohne alle Vorkommen zu ersetzen?

    Sehr gut, da passt jemand auf 😉

    Edit:
    Im Gegensatz zu mir. Hab´ die Aufgabe nur überflogen und überheblicherweise angenommen, das hätte gereicht und ich die Aufgabe verstanden. Pustekuchen...



  • Und wenn du ostream durch std::ostream ersetzen würdest (oder ein using machen würdest), dann würde das auch kompilieren. Macht schon Spaß, einen virtuellen Wald an mehreren Stellen anzustecken und zu schauen, wie sich das Feuer ausbreitet 🕶



  • Hi Leute! Danke für eure Antworten. Da sind für mich echt ein paar gute Lösungsansätze dabei. Ich versuche jetzt erstmal das alles aufzunehmen und umzusetzen und melde mich dann noch einmal mit der (hoffentlich) Lösung 🙂



  • Soo! Geschafft! Vielen lieben Dank an alle die geholfen haben!

    Belli seine Antwort hat sehr geholfen. DocShoe´s Antwort funktioniert auch super, allerdings muss ich das Programm auch vorstellen und da sollte ich dann mit meinem eigenen kommen, sonst gibts bestimmt bei Fragen Probleme.

    Hier mal meine Schleife mit der das ganze nun läuft

    for(i=0; i<20; i++)
            {
                // Schleife fuer Spalten, X-Achse
                for(k=0; k<30; k++) {
    
    		if(Wald[i][k]=='+')Wald[i][k]='-';
    
                if(Wald[i][k]=='-'&&Wald[i+1][k]=='X'||Wald[i][k]=='-'&&Wald[i-1][k]=='X'||Wald[i][k]=='-'&&Wald[i][k+1]=='X'||Wald[i][k]=='-'&&Wald[i][k-1]=='X'){
    
                    if(Wald[i+1][k]=='X')Wald2[i+1][k]='+';
                    if(Wald[i-1][k]=='X')Wald2[i-1][k]='+';
                    if(Wald[i][k+1]=='X')Wald2[i][k+1]='+';
                    if(Wald[i][k-1]=='X')Wald2[i][k-1]='+';
                }
                }
    
            }
    
            for(i=0;i<20;i++)
            {
                for(k=0;k<30;k++)
                {
                    if(Wald2[i][k]=='+')Wald[i][k]='+';
                    if(Wald2[i][k]=='+')Wald2[i][k]='-';
                }
            }
    
            for(i=0;i<20;i++){
                for(k=0;k<30;k++){
               		cout<<Wald[i][k]<<" ";
    
                }
          	cout<<endl;
            }
    


  • Du greifst immer noch auf Speicher außerhalb der Arraygrenzen zu.



  • Oh... Das Problem mit [0-1] richtig?

    Ich Sehe gerade, dass wenn ich nur den ersten Baum im brand setze, der Wald auch von rechts nach Links abbrennt.

    https://imgur.com/4XaH68Z

    Hab ich jetzt mal so gelöst:

    if(Wald[i][0]){}
                    else{
                    if(Wald[i][k-1]=='X')Wald2[i][k-1]='+';
                    }
    

    Funktioniert aber auch nicht richtig 🙄

    Edit:

    Okay jetzt aber. Ich hab eine Schleife extra für (k=0;k<1;k++) und den Rest in eine Schleife (k=1;k<30;k++)

    Ihr seid die besten 🙂



  • b4mbus schrieb:

    Mit dem Thema Debugger werd ich mich mal auseinander setzen. Ich hab keine Ahnung noch wie das geht.

    sowas macht man eigentlich gleich nach "hallo welt!". vereinfacht gesagt klickst du auf den bereich neben der zeilennummer, damit da ein roter punkt o.ä. erscheint und dann wählst du "debuggen" aus. wenn der code dann an die stelle mit dem roten punkt angelangt ist, bleibt das programm stehen und du kannst dir den inhalt der variablen ansehen. damit ersparst du dir eine menge arbeit.



  • wob schrieb:

    Und wenn du ostream durch std::ostream ersetzen würdest (oder ein using machen würdest), dann würde das auch kompilieren.Feuer ausbreitet
    ...

    Jo, stimmt. Komischerweise übersetzt und läuft das bei mir so. Hab´s jetzt korrigiert.
    Das Embarcadero RAD Studio ist wohl besser als C++, weil der Compiler einige Sachen korrigieren kann 😃



  • @bamb4s

    Um eine Fehlerquelle komplett auszumerzen (Zugriff auf ungültige Arrayelemente) solltest du dir zwei Funktionen bauen: Eine, die den Wert eines Arrayelements zurückgibt und eine, die den Wert eines Arrayelements setzt. Wenn du in diesen beiden Funktionen eine Gültigkeitsprüfung der Indizes vor dem Arrayzugriff durchführst kannst du nicht mehr auf ungültige Arrayelemente zugreifen.

    char tree_state( std::size_t x, std::size_t y )
    {
       if( x < DimX && y < DimY ) return Wald[x][y];
       else                       return 0;
    }
    
    void set_tree_state( std::size_t x, std::size_t y, char NewState )
    {
       if( x < DimX && y < DimY ) 
       {
          Wald[x][y] = NewState;
       }
    }
    


  • DocShoe schrieb:

    lol?

    Wieso lol? Vielleicht habe ich die Aufgabe auch falsch verstanden, aber wenn Bäume nur eine Runde brennen, ist dies in Relation zur Gesamtfläche sehr wenig. Außerdem weiß man so auch, wann man ferig ist. Das sieht bei den geposteten Codes eher nicht so aus.
    Ich werde das mal testen...



  • Wenn man zwischen brennend und abgebrannt unterscheiden muss, muss man den floodfill doch ein wenig anpassen.

    Stack 1 enthält brennende Bäume (am Anfang drei - rot), diese suchen sich Nachbarn (im Link unten acht, also auch diagonal) zum Entzünden. Werden welche gefunden, werden die Punkte auf Stack 2 gepusht.
    Eine „Runde” ist dann beendet, wenn Stack 1 komplett abgebaut wurde. Der Inhalt von Stack 2 wird kopiert (die entzündeten sind nun die brenndenden Bäume) und die Koordinaten entsprechend markiert (gelb).
    Anschließend wird ein Bild gemacht.

    Das gif ist leider etwas groß geworden (~2MB). Es sind drei Runden mit gleichen Startpunkten aber einer unterschiedlichen Anzahl an Bäumen (Karte 120*80).



  • Wenn kein Baum mehr brennt ist man fertig, das kriegt man auch ohne Stack raus.


Anmelden zum Antworten