Laden...

Algorithmus für Jeder-gegen-Jeden

Erstellt von schweito vor 2 Jahren Letzter Beitrag vor 2 Jahren 454 Views
S
schweito Themenstarter:in
5 Beiträge seit 2015
vor 2 Jahren
Algorithmus für Jeder-gegen-Jeden

Liebe C#-Gemeinde,

leider ist mein Titel ein wenig diffus - aber ich wollte eben alle Seiten "meines" aktuellen Problems nennen. Ich arbeite aktuell an einem Algorithmus der folgende bewerkstelligen soll:

Erstellen einer beliebigen Anzahl an Kämpfern

  • Jeder Kämpfer wird als Objekt in einer Schleife generiert.
  • Jeder Kämpfer bekommt eine "Kampfhistorie" in der er gegen zufällige Gegner kämpft.
  • Gewinnt der Kämpfer wird es bei ihm entsprechend vermerkt - und beim Gegner entsprechend invertiert.
  • Der Kämpfer darf nicht gegen sich selbst kämpfen dürfen (Ich habe versucht, dies durch ein inkrement zu lösen : k++).

Ich habe aktuell das Problem, dass die Paarungen und Resultat nicht korrekt gespeichert werden. Manchmal kommt das Problem das in der Datei : "Jack" zb. dreimal der Gegner
"Mike" gelistet wird. Bei Mike stehen aber nur zweimal "Jack".

Anbei der Code, ich weiß aktuell nicht, wie ich es besser beschreiben könnte:


 public void Generate_History()
    {
        String fighter1, fighter2; //Kämpfer, Gegner
        int result; //Resultat
        int start_pos = 0;   //Erster Kämpfer der Liste
       
        int k; //Späterer Index für die Gegnerwahl
        Opponent[] fighter = new Opponent[9]; //Erstelle 9 Kämpfer
        
        
        string path = @"C:/Users/korre/Documents/source_modified/source/repos/BoxingManager/BoxingManager/Data/";
        
        for (int i = 0; i < 8; i++) //Erstelle zum Testen 9 Kämpfer
        {
            fighter[i] = new Opponent();
        }

        while (start_pos < 8)
        {
            for (int i = 0; i < 8; i++) // Solange noch nicht jeder gekämpft hat
            {
                k = GetRandomNumber(0, 8);  //Zufällige Gegnerwahl
                result = GetRandomNumber(0, 4); //Zufälliges Resultat
                if (k == start_pos) //Kämpfer und Gegner dürfen nicht gleich sein. Prüfen und k ändern: Idee k++
                {
                    
                    k ++;

                }
                else //Kämpfer und Gegner sind ungleich
                {
                    
                    //Schreibe den aktuelle Kämpfer (linken Teil der Paarung) in die Variable fighter1 / Start_pos beschreibt den Index für den linken Teil der Paarung und ändert sich 
                   //nachdem gegen ein bestimmter Boxer gegen alle Kämpfer der Liste gekämpft hat
                  
                     fighter1 = fighter[start_pos].firstNames[start_pos] + " '" + fighter[start_pos].nickNames[start_pos] + "' " + fighter[start_pos].lastNames[start_pos];

                    //Schreibe den zufälligen Gegner (rechten Teil der Paarung) in die Variable fighter2 / k ist zufällig und wird durch GetRandomNumber ermittelt.
                   
                    fighter2 = fighter[k].firstNames[k] + " '" + fighter[k].nickNames[k] + "' " + fighter[k].lastNames[k];
                    


                    
                    //Kämpfer: Es wird die Datei mit dem Dateinamen des Kämpfer angelegt und als Inhalt der Gegnername und das Resultat gespeichert.
                    
                    using (StreamWriter sw = File.AppendText(path + fighter[start_pos].firstNames[start_pos] + "_" + fighter[start_pos].nickNames[start_pos] + "_" +   
                    fighter[start_pos].lastNames[start_pos]+".txt"))
                    {
                        sw.WriteLine(fighter2 + "," + result); //Schreibe bei Kämpfer den Namen des Gegners und das Resultat

                    }
                    //Gegner: Es wird die Datei mit dem Dateinamen des Gegners angelegt und als Inhalt der Kämpfers und das Resultat gespeichert.
                    
                    using (StreamWriter sw = File.AppendText(path + fighter[k].firstNames[k] + "_" + fighter[k].nickNames[k] + "_" + fighter[k].lastNames[k]+".txt"))
                    {
                        if (result == 0) // 0: Gewonnen nach Punkten Kämpfer  ; 2: Verloren nache Punkten Gegner
                        {
                            result = result + 2;
                            sw.WriteLine(fighter1 + "," + "2"); //Schreibe beim Gegner, den Namen des Kämpfers uns das Resultat (Invertiertes Resultat)
                        }

                        if (result == 1)  // 1; Gewonnen durch KO Kämpfer; 3: Verloren durch KO Gegner
                        {
                            result = result + 2;
                            sw.WriteLine(fighter1 + "," + "3"); 
                        }

                        if (result == 2) // 2: Verloren nache Punkten Kämpfer  ; 0: Gewonnen nach Punkten Gegner
                        {
                            result = result - 2;
                            sw.WriteLine( fighter1 + "," + "0");
                        }

                        if (result == 3) //3: Verloren durch KO Kämpfer; 1: Gewonnen durch KO Gegner
                        {
                            result = result - 2;
                            sw.WriteLine(fighter1 + "," + "1");
                        }

                        if (result == 4) // 4: Unentschieden
                        {
                            sw.WriteLine(fighter1 + "," + "4");
                        }
                    } 

                }   
             };

           

            start_pos++; //Nehme einen neuen Kämpfer 
        }

        



    }

Ich finde meine Fehler aktuell nicht und wäre denkbar, für etwaige Denkanstöße, oder Vereinfachungen.

Viele Grüße und vielen Dank,
schweito

Hinweis von Abt vor 2 Jahren

Ich hab den Titel so angepasst, dass man wenigstens etwas damit anfangen kann

J
61 Beiträge seit 2020
vor 2 Jahren

Auch wenn ich dir auf die Schnelle nicht weiterhelfen kann, aber

  
  
for (int i = 0; i < 8; i++) //Erstelle zum Testen 9 Kämpfer  
  
  

sind 8 Durchläufe, also nur 8 Kämpfer.

4.931 Beiträge seit 2008
vor 2 Jahren

Hallo,

da paßt m.E. einiges an der Logik nicht.
Du solltest ersteinmal genau definieren, wie viele Kämpfe ausgetragen werden sollen und wer gegen wen kämpfen soll.
Bis jetzt führst du 64 (8 * 8) Kämpfe durch und läßt jeden Kämpfer (start_pos) mit 8 zufällig ausgewählten Gegnern kämpfen. Und durch die Einschränkung k == start_pos übergeht der Code dann jeweils einen Kampf (das k++ ist hier bislang nutzlos, da der else-Code dann ja nicht ausgeführt wird).

Warum die Zuordnung der Namen in den Dateien unterschiedlich ist, kann ich dir auf Anhieb auch nicht sagen (s. nächster Satz), aber du könntest in der Konsole ja einfach beide Namen jeweils ausgeben oder alternativ mittels [Artikel] Debugger: Wie verwende ich den von Visual Studio? deinen Code schrittweise abarbeiten.

Der Code würde auch viel übersichtlicher werden, wenn du Teile davon in eigene Methoden auslagern würdest (Logik und IO gehören normalerweise zusammen nicht in eine Methode).

PS: Deine Namenszuordnung innerhalb der Opponent-Klasse über die Listen-Eigenschaften firstNames, nickNames und lastNames zeigen, daß du OOP falsch anwendest. Jedes Opponent-Objekt sollte selbst je eine Eigenschaft für die 3 Namensteile haben!
Du bräuchtest dann auch nicht so komplizierte Stringkonkatenationen durchführen, wenn diese Objekte passende Eigenschaften für die Gesamtnamen (FullName) hätten.
Und auch das Rausschreiben des result machst du zu kompliziert...

S
schweito Themenstarter:in
5 Beiträge seit 2015
vor 2 Jahren

Hallo @all,

danke für die schnelle Antworten - ich sehe das auch so - die Logik ist noch ein bisschen fehlerhaft. Ich werde die Links lesen - eine Frage vorab - wie sollte ich denn sonst ausschließen, dass der Kämpfer nicht gegen sich selbst kämpft, wenn nicht mit der Prüfung start_pos==k ?

Viele Grüße,
schweito

4.931 Beiträge seit 2008
vor 2 Jahren

An sich ist die Abfrage nicht falsch, aber die Frage ist: was soll dann passieren? Denn bei dir könnte es ja theoretisch sein, daß dann kein (bzw. kaum ein) Kampf stattfindet, wenn zufällig öfter diese Zahl "gewürfelt" wird. Du könntest z.B. einfach solange ziehen, bis diese Zahl unterschiedlich ist (so daß immer eine konstante Anzahl von Kämpfen stattfindet).

PS: Die unteren Links sind einfach meine Signatur (d.h. für dich jetzt noch nicht interessant) - in der alten Forensoftware war dies klarer ersichtlich.

J
61 Beiträge seit 2020
vor 2 Jahren

Dass das Schreiben nicht wie von dir erwartet funktioniert, liegt daran, dass z.B. beim Ergebnis 3 „nur“ 3 betrachtet wird. Bei Ergebnis 1 betrachtest du 1 und 3.

Die Abarbeitung des Codes ändert eben nicht einfach durch Substraktion bei „result“ die Richtung.

4.931 Beiträge seit 2008
vor 2 Jahren

Das ist eher eine ungewollte Codeausführung - es soll ja nur genau 1 Kampfergebnis abgespeichert werden.
Es fehlen jeweils else vor den if (result == ...)-Anweisungen und bisher sind die Änderungen von result auch unnötig, da der gegensätzliche Wert ja direkt als String abgespeichert wird. Besser wäre aber das komplette Neuschreiben (und Aufteilen in 2 Methoden).

S
schweito Themenstarter:in
5 Beiträge seit 2015
vor 2 Jahren

Hallo @alle,

vielen Dank - ich werde mir die Antworten und Ideen zu Herzen nehmen und den Code neuschreiben - er ist eh unübersichtlich.

Viele Grüße,
schweito

O
79 Beiträge seit 2011
vor 2 Jahren
  
  
for (int i = 0; i < 8; i++) //Erstelle zum Testen 9 Kämpfer  
  
  

sind 8 Durchläufe, also nur 8 Kämpfer.

das ist in dem später folgenden

k++;

begründet. Dieser (leider untaugliche, aber der TE ist ja Anfänger) Winkelzug hat die Überschreitung der Arraygrenzen, auf die der TE bei seinen ersten Tests garantiert gestoßen ist, erstmal behoben. Blöd nur, das Kämpfer 9 niemals als fighter1 zum Zuge kommen wird dadurch.

Besser wäre gewesen:


do
    k = GetRandomNumber(0,8); 
while (k != startpos);

S
schweito Themenstarter:in
5 Beiträge seit 2015
vor 2 Jahren

Liebe C-sharp-Community,

ich habe gestern versucht Eure Anregungen umzusetzen und Teile neu geschrieben. Nun habe ich zwei Probleme:

1.) Fehlermeldung: "Der Index darf nicht kleiner als die Sammlung sein"
Kommt bei Zeile 67 in der die Datei erstellt oder erweitert werden sollte.

  1. Der zweite Fehler : Kämpfe gegen sich selbst sind nun leider möglich.(Lt. Dateiinhalt)

Ich bin wie folgt vorgegangen:

Der aktuelle Kämpfer wird als Datei angelegt und dann temporär in ein Dictionary gespeichert und von der Liste entfernt. Ich dachte damit, die Abfrage wie
k==start_pos weglassen zu können, da der aktuelle Kämpfer nicht mehr in der Liste ist und somit nicht gegen sich selbst kämpfen kann. Nachdem die Liste einmal durchgegangen wurde und die Paarungen fertig sind, wird das Element wieder in die Liste zurückgeschrieben und der Inhalt der List ist wieder wie vorher. Das scheint so aber nicht zu gehen. Der bisherige Vorteil ist, dass die Komplexität heruntergegangen ist er bricht aber bei element=7 lt. Debugger ab.


public static void CreateHistory()
    {

        List<string> fighter = new List<string>() { "Johnson", "Peters", "Lidell", "McCall", "Jackson", "Henderson", "Clark", "Monroe" };
        Dictionary<string, int> ExcludedFighter = new Dictionary<string, int>(); //Enthält den zu entfernenden Kämpfer
        int element = 0, opponent, result;

        
        

        while (element < fighter.Count)
        {

            // ----------------------------------------------------------------------------------------------------------------------
            //| In diesem Abschnitt wird die Liste "fighter" durchgegangen und das aktuelle Element (der aktuelle Kämpfer)
            //| temporär in einem Dictionary gespeichert inkl. der Position, um diesen Kämpfer aus der Liste der Gegner zu nehmen.
            //| So sollen Kämpfe mit sich selbst vermieden werden.
            //|-----------------------------------------------------------------------------------------------------------------------

            ExcludedFighter.Add(fighter[element], element); //Dictionary: Aussortierter Kämpfer und Index

            
            fighter.RemoveAt(element); //Entferne temporär den aktuellen Kämpfer aus der Liste

            for (int i=0;i<fighter.Count;i++) //Gehe durch die Liste der Kämpfer
            {
                opponent = GetRandomNumber(0,fighter.Count); //Gegner wird zufällig ermittelt
                result = GetRandomNumber(0, 4); //Resultat wird zufällig ermittelt
                
                using (StreamWriter w = File.AppendText("C:/Users/korre/Documents/source_modified/source/repos/BoxingManager/BoxingManager/Data/"+fighter[element] + ".txt")) //Schreibe die Kämpferdatei
                {
                    w.WriteLine(fighter[opponent]+","+result);
                }

                using (StreamWriter w = File.AppendText("C:/Users/korre/Documents/source_modified/source/repos/BoxingManager/BoxingManager/Data/" + fighter[opponent] + ".txt")) //Schreibe die Gegnerdatei
                {
                    if (result == 0)
                    {
                        w.WriteLine(fighter[element] + "," + "2");
                    }

                    if (result == 1)
                    {
                        w.WriteLine(fighter[element] + "," + "3");
                    }

                    if (result == 2)
                    {
                        w.WriteLine(fighter[element] + "," + "0");
                    }

                    if (result == 3)
                    {
                        w.WriteLine(fighter[element] + "," + "1");
                    }
                    if (result == 4)
                    {
                        w.WriteLine(fighter[element] + "," + "4");
                    }

                }


            }


            foreach (var pair in ExcludedFighter) //Ermittele das gelöschte Element in der Dictionary
            {
                fighter.Insert(pair.Value, pair.Key);  //Schreibe das temporär gelöschte Element zurück in die Liste
            }
            ExcludedFighter.Clear();
            element++;

        }
    }

Viele Grüße und vielen Dank bislang, Ich habe das Gefühl als habe ich ein bisschen was gelernt bisher auch wenn es wohl nicht danach aussieht.
schweito

4.931 Beiträge seit 2008
vor 2 Jahren

Überlege mal was beim letzten Fighter (element = fighter.Count - 1) passiert (da du ja jeweils den aktuellen Fighter aus der Liste löschst)? Verwende einfach den Debugger ("watch window"/"Überwachte Ausdrücke"), sobald die Exception erscheint, um die Werte anzuzeigen.

Aber das ganze Löschen und Wiederhinzufügen ist überflüssig, wenn du den Code von @OlafSt benutzt (so wie ich es auch schon beschrieben hatte). Dann sind beide Fehler aus der Welt.

PS: Absolute Pfadangaben (als String-Literale) solltest du nicht verwenden (da es ja dann nur auf deinem Rechner funktioniert). Verwende Application.StartupPath mit relativen Pfaden (mittels Path.Concat(...) zusammengesetzt). Das "Data"-Verzeichnis sollte dann auch ein Unterverzeichnis des Ausgabeverzeichnisses ("bin/Debug" bzw. "bin/Release" sein).

Und wie ich mir die Auslagerung als eigene Methode vorstelle:


WriteFight(fighter[element], fighter[opponent], result);

if (result == 0)
  result += 2;
else if (result == 1)
  result += 2;
else ...

WriteFight(fighter[opponent], fighter[element], result);

Jetzt mußt du nur noch WriteFighter implementieren...