Spieltaggenerierung für Liga



  • Moinmoin,

    ich versuche gerade mal dem Rat meines Arbeitskollegen zu folgen und einfach mal ein paar kleine Programme zu schreiben um mal meine C++ Basiskenntnisse zu festigen und dann vielleicht mal auszubauen. Da wir gerade eine kleine Spielliga machen wollen und ich mich schon 2x mit der manuellen Gestalltung rumgeärgert habe dachte ich mir, schreibste kurz mal ein Programm. Jetzt hab ich da irgendwo aber nen Bug drin und ich seh ihn einfach nicht...

    Das Programm wird in der Konsole beendet mit:
    "terminate called after throwing an instance of "std::out_of_range"
    what (): vector::_M_range_check"

    Ich vermute also mal ich versuche irgendwo auf Vektorelemente zuzugreifen die nicht da sind(?)

    #include <iostream>
    #include <vector>
    #include <string>
    #include <fstream>
    
    int main()
    {
    	std::vector <std::string> Teilnehmer;
    /****************************************************************/
    /* Das Programm generiert eine Spielplan analog zur Bundesliga.	*/
    /* Bei einer ungeraden Spielerzahl muss bei "Joker" das Freilos	*/
    /* eingetragen werden, bei einer geraden Spielerzahl muss hier	*/
    /* ein regulärer Spieler eingetragen werden.					*/
    /****************************************************************/
    
    	std::string Joker = "Freilos";
    
    /****************************************************************/
    /* Ligateilnehmer eingeben										*/
    /****************************************************************/
    
    	Teilnehmer.push_back ("Spieler1");
    	Teilnehmer.push_back ("Spieler2");
    	Teilnehmer.push_back ("Spieler3");
    	Teilnehmer.push_back ("Spieler4");
    	Teilnehmer.push_back ("Spieler5");
    
    /****************************************************************/
    /* Jetzt kompilieren, ausführen und glücklich sein				*/
    /****************************************************************/
    
    	int Teilnehmerzahl = Teilnehmer.size() +1;
    
    	std::ofstream Ligaspielplan;
    	Ligaspielplan.imbue(std::locale(""));
    	Ligaspielplan.open("Ligaspielplan.txt");
    	if (Ligaspielplan.is_open())
    	{
    	for (int Spieltag=1; Spieltag<=Teilnehmerzahl; ++Spieltag)
    	{
    		std::vector<int> gepaarteSpieler;
    		Ligaspielplan <<"Spieltag " <<Spieltag<<"\n\n";
    		for (int j=1;j<=Teilnehmerzahl; ++j)
    		{
    			//soll verhindern, dass die Spiele doppelt generiert werden
    			bool check=0;
    			for (int x=0; x<gepaarteSpieler.size();++x)
    			{
    				if(gepaarteSpieler.at(x)==j)check=1;
    			}
    			if(check==0)
    			{
    				//sucht den passenden Gegenspieler für den entsprechenden Spieltag
    				for (int i=1; i<=Teilnehmerzahl; ++i)
    				{	
    					if(((i+j)%Teilnehmer.size())==Spieltag)
    					{
    						Ligaspielplan << Teilnehmer.at(j-1) <<" - " << Teilnehmer.at(i-1)<<"\n";
    						gepaarteSpieler.push_back(i);
    						gepaarteSpieler.push_back(j);
    						check=1;
    						break;
    					}
    				}
    				//wenn kein Gegenspieler gefunden wurde, wird der Joker gesetzt
    				if(check==0) Ligaspielplan << Teilnehmer.at(j-1) <<" - " << Joker <<"\n";
    			}
    		}
    		Ligaspielplan <<"\n\n\n";
    	}
    }
    return 0;
    }
    


  • Als Sofortdiagnose sieht es mir so aus, als ob deine Schleife eins zu weit laufen würde. Was sagt denn der Debugger?



  • Beim zweiten Blick wird es offensichtlich: Die Indizes eines std::vector gehen von 0 bis size()-1. Bei dir laufen sie von 1 bis size().



  • Kopf->Tisch

    danke... aber jetzt hab ich irgendwie das Problem das da irgendwas grundlegend wohl nicht stimmt, am letzten Spieltag generiert er mir keine Paarung mehr...

    #include <iostream>
    #include <vector>
    #include <string>
    #include <fstream>
    
    int main()
    {
    	std::vector <std::string> Teilnehmer;
    /****************************************************************/
    /* Das Programm generiert eine Spielplan analog zur Bundesliga.	*/
    /* Bei einer ungeraden Spielerzahl muss bei "Joker" das Freilos	*/
    /* eingetragen werden, bei einer geraden Spielerzahl muss hier	*/
    /* ein regulärer Spieler eingetragen werden.					*/
    /****************************************************************/
    
    	std::string Joker = "Freilos";
    
    /****************************************************************/
    /* Ligateilnehmer eingeben										*/
    /****************************************************************/
    
    	Teilnehmer.push_back ("1");
    	Teilnehmer.push_back ("2");
    	Teilnehmer.push_back ("3");
    
    /****************************************************************/
    /* Jetzt kompilieren, ausführen und glücklich sein				*/
    /****************************************************************/
    
    	int Teilnehmerzahl = Teilnehmer.size() +1;
    
    	std::ofstream Ligaspielplan;
    	Ligaspielplan.imbue(std::locale(""));
    	Ligaspielplan.open("Ligaspielplan.txt");
    
    	for (int Spieltag=1; Spieltag<Teilnehmerzahl; ++Spieltag)
    	{
    		std::vector<int> gepaarteSpieler;
    		Ligaspielplan <<"Spieltag " <<Spieltag<<"\n\n";
    		for (int j=1;j<Teilnehmerzahl; ++j)
    		{
    			//soll verhindern, dass die Spiele doppelt generiert werden
    			bool check=0;
    			for (int x=0; x<gepaarteSpieler.size();++x)
    			{
    				if(gepaarteSpieler.at(x)==j)check=1;
    			}
    			if(check==0)
    			{
    				//sucht den passenden Gegenspieler für den entsprechenden Spieltag
    				for (int i=1; i<Teilnehmerzahl; ++i)
    				{	
    					if(((i+j)%Teilnehmer.size())==Spieltag)
    					{
    						gepaarteSpieler.push_back(j);
    						if(i==j) Ligaspielplan << Teilnehmer.at(j-1) <<" - " << Joker <<"\n";
    						else
    						{
    							Ligaspielplan << Teilnehmer.at(j-1) <<" - " << Teilnehmer.at(i-1)<<"\n";
    							gepaarteSpieler.push_back(i);
    						}
    
    					}
    
    				}
    				//wenn kein Gegenspieler gefunden wurde, wird der Joker gesetzt
    
    			}
    		}
    		Ligaspielplan <<"\n\n\n";
    	}		
    }
    

    Spieltag 1

    1 - 3
    2 - Freilos

    Spieltag 2

    1 - Freilos
    2 - 3

    Spieltag 3



  • Ohne deinen Code jetzt wirklich nachvollziehen zu wollen, kann ich dir verraten, dass die Spielplangenerierung nicht ganz so trivial ist, wie man auf den ersten Blick meinen würde. Eine sehr anschaulich beschriebene Lösung des Problems findest du hier.



  • Deine Schleifen sehen auch komisch aus:
    Du beginnst jeweils bei 1 mit dem Zählen und gehst solange kleiner n. Und da die Indizes auch um 1 verringerst, lässt du irgendwo ein Element aus (am Ende).



  • Moin ananas,

    jupp, das habe ich auch schon festgestellt, dass der Algorithmus komplizierter ist 😃

    Also mal um das Vorgehen zu erklären:

    Ich habe x Teilnehmer (sagen wir hier 4) (gerade Zahl, im Zweifel durch ein Freilos hergestellt).

    3 der Teilnehmer werden in einem Vektor gespeichert (und damit eine Zahl von 1-3 zugewiesen, deswegen laufen meine Schleifen bei 1 los), der 4 wird der Joker.

    An einem Spieltag spielen jetzt Teilnehmer i und j gegeneinander, so dass der modulo durch 3 (Gesamtzahl der Leute im Vektor) dem aktuellen Spieltag entspricht (und hier fällt mir auf könnte auch schon der fehler am letzten Spieltag liegen... hier müsste ein Spezialfall für modulo = 0 hergestellt werden, oder?). Dadurch findet genau einer der Teilnehmer im Vektor keinen Spielpartner, der spielt dann gegen den Joker.

    Dazu speicher ich noch alle gepaarten Spieler an einem Spieltag in dem Vektor "gepaarteSpieler" weil ansonsten ja jede Paarung 2x auftreten würde (außer die gegen den Joker).

    Du beginnst jeweils bei 1 mit dem Zählen und gehst solange kleiner n. Und da die Indizes auch um 1 verringerst, lässt du irgendwo ein Element aus (am Ende).

    Jupp, allerdings ist die Teilnehmerzahl um eins größer als die Anzahl der Einträge im Vektor. Ich weiß, das ist etwas... Gehirnarbeit...



  • Ja ist es etwas, aber ich hab mich auch nicht in dein Programm reingedacht und kann so zu nicht-offensichtlichen Fehlern nichts sagen.

    Ich weiss nur noch damals aus der Schule, dass dieses Problem nicht ganz trivial sit wie es zu sein scheint. (War da nicht ne Komplexität von O(n!) oder sowas? kA mehr)



  • So, das mit dem Modulo war genau der Fehler, am letzten Spieltag muss der Modulo gleich 0 sein. Programm funktioniert, danke für die Hilfe und die Denkanstöße 🙂 Anbei nochmal das laufende Programm, ich wollte jetzt auch nochmal mit GUI´s experimentieren, vermutlich werde ich es dann auch damit mal aufhübschen 🙂

    #include <iostream>
    #include <vector>
    #include <string>
    #include <fstream>
    
    int main()
    {
    	std::vector <std::string> Teilnehmer;
    /****************************************************************/
    /* Das Programm generiert eine Spielplan analog zur Bundesliga.	*/
    /* Bei einer ungeraden Spielerzahl muss bei "Joker" das Freilos	*/
    /* eingetragen werden, bei einer geraden Spielerzahl muss hier	*/
    /* ein regulärer Spieler eingetragen werden.					*/
    /****************************************************************/
    
    	std::string Joker = "Freilos";
    
    /****************************************************************/
    /* Ligateilnehmer eingeben										*/
    /****************************************************************/
    
    	Teilnehmer.push_back ("1");
    	Teilnehmer.push_back ("2");
    	Teilnehmer.push_back ("3");
    
    /****************************************************************/
    /* Jetzt kompilieren, ausführen und glücklich sein				*/
    /****************************************************************/
    
        int Teilnehmerzahl = Teilnehmer.size() +1;
    
        std::ofstream Ligaspielplan;
        Ligaspielplan.imbue(std::locale(""));
        Ligaspielplan.open("Ligaspielplan.txt");
        bool check;
        int Modulo;
    
        for (int Spieltag=1; Spieltag<Teilnehmerzahl; ++Spieltag)
        {
            std::vector<int> gepaarteSpieler;
            Ligaspielplan <<"Spieltag " <<Spieltag<<"\n\n";
            for (int j=1;j<Teilnehmerzahl; ++j)
            {
                //soll verhindern, dass die Spiele doppelt generiert werden
                bool check=0;
                for (int x=0; x<gepaarteSpieler.size();++x)
                {
                    if(gepaarteSpieler.at(x)==j)check=1;
                }
                if(check==0)
                {
                    //sucht den passenden Gegenspieler für den entsprechenden Spieltag
                    for (int i=1; i<Teilnehmerzahl; ++i)
                    {  
                    	Modulo=Spieltag;
                    	if(Modulo==Teilnehmer.size())Modulo=0;
                        if(((i+j)%Teilnehmer.size())==Modulo)
                        {
                            gepaarteSpieler.push_back(j);
                            if(i==j) Ligaspielplan << Teilnehmer.at(j-1) <<" - " << Joker <<"\n";
                            else
                            {
                                Ligaspielplan << Teilnehmer.at(j-1) <<" - " << Teilnehmer.at(i-1)<<"\n";
                                gepaarteSpieler.push_back(i);
                            }
    
                        }
    
                    }
                    //wenn kein Gegenspieler gefunden wurde, wird der Joker gesetzt
    
                }
            }
            Ligaspielplan <<"\n\n\n";
        }      
        return 0;
    }
    

Log in to reply