Aktuelle Array Position



  • Hallo Leute!

    Ich hab da ein kleine Problem und komme trotz Sucherei im www leider nicht weiter 😞

    Ich habe die Aufgabe für das Testat an der Uni ein Waldbrand in einem Programm zu erzeugen. Das funktioniert auch recht gut, bis auf eine Sache.

    Ich habe ein Array Wald[i][k] Bäume sind 'X' brennende Bäume '+' und abgebrante Bäume '-'

    Wenn jetzt ein Baum brennt soll er seine umstehenden Bäume anzünden, also quasi Wald[i+1][k], Wald[i-1][k], Wald[i][k+1],Wald[i][k-1].

    Das funktioniert aber leider nur für die Bäume rechts und darunter 😞 Die Bäume drüber und links von der aktuellen Position werden nicht angezündet..

    https://imgur.com/a/deODo
    Im Bild kann man sehen, dass auf der aktuellen Position der obere Baum nicht angezündet wird

    for(i=0; i<20; i++) {
                // Schleife fuer Spalten, X-Achse
                for(k=0; k<30; k++) {
    
                if(c > schritt){
    
                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')Wald[i+1][k]='+';
                    if(Wald[i-1][k]=='X')Wald[i-1][k]='+';
                    if(Wald[i][k+1]=='X')Wald[i][k+1]='+';
                    if(Wald[i][k-1]=='X')Wald[i][k-1]='+';
    
                }
    
                if(Wald[i][k]=='+')Wald[i][k]='-';
    
               schritt++;
    
                }
    
    		cout<<Wald[i][k]<<" ";
    
                }
    	cout<<endl;
    
            }
    

    Ich hoffe es kann mir jemand helfen. Sollte ich noch was vergessen haben hier rein zu schreiben sagt es mir, dann trage ich es nach.

    Danke schonmal!



  • Wenn ich das auf die Schnelle richtig sehe, dann sind die Bäume [i-1][k] und [i][k - 1] doch schon auf dem Bildschirm ausgegeben, wenn Du sie als brennend kennzeichnest?!



  • Du greifst auf Werte außerhalb des Arrays zu. Was ist z.B. i-1 für i==0?
    Benutze einen Debugger.



  • Sorry aber ich kann der Aussage grade nicht folgen. In dem Moment wenn die Schleife auf die aktuelle Position springt (siehe Bild) wird der Baum darunter angezündet. Der rechts daneben brennt ja schon von dem Baum darüber. Aber der darüber wurde werder in dem aktuellen Schritt angezündet, noch in dem Schritt i-1



  • manni66 schrieb:

    Du greifst auf Werte außerhalb des Arrays zu. Was ist z.B. i-1 für i==0?
    Benutze einen Debugger.

    Ich dachte mir so etwas schon. Allerdings weiß ich nicht wie ich sowas umgehen kann.

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



  • Der Baum darüber ist doch schon einen Schleifendurchlauf vorher, als i noch eins kleiner war, auf dem Bildschirm ausgegeben worden, und zu dem Zeitpunkt hat er noch nicht gebrannt.
    Nun, in diesem Durchlauf setzt Du [i-1][k] auf '+', aber dieser Baum wird doch nicht mehr ausgegeben, sondern cout gibt doch immer nur den aktuellen Baum aus.
    Deshalb siehst Du auch nur, dass der rechte und der untere Baum angezündet werden, denn die werden erst noch, beim nächsten k, bzw. beim nächsten i, ausgegeben.



  • Oh verdammt. Stimmt! Die Ausgabe ist ja schon vorbei.... Verdammt, dann muss ich ja alles über den Haufen werfen hier, denn die Ausgabe wurde ja schon gemacht 😮 😮 😮



  • Gibts den keine Möglichkeit das aktuelle Array auszugeben und nicht immer die einzelnen Schritte?



  • Klar, nimm die couts aus der Schleife und mach dahinter noch mal eine Schleife, in der nur die couts stehen, so dass Du zuerst das ganze Array neu berechnest, und danach gibst Du es in einem Rutsch aus.



  • 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?



  • 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 🕶


Anmelden zum Antworten