Laden...

rekursive Methode wirft ArgumentOutOfRange

Erstellt von bloody_fighter vor 12 Jahren Letzter Beitrag vor 12 Jahren 1.890 Views
B
bloody_fighter Themenstarter:in
54 Beiträge seit 2008
vor 12 Jahren
rekursive Methode wirft ArgumentOutOfRange

Guten Tag,
ich habe eine Rekursive funktion geschrieben und finde einfach nicht, warum sie nicht funktioniert (immer nach einigen "durchläufen" eine ArgumentOutOfRange Exception wirft)...
Nach 20 mal Debuggen bin ich langsam am verzweifeln und hoffe, dass sich jemand von euch mal die Zeit nimmt, sich das anzuschauen!


private void hinzufuegen(TreeNode bknoten, List<List<Karte>> karten, 
            List<Karte> stich, int bspielerDerDranIst ,int vorhand)
        {
            TreeNode knoten = bknoten;
            int spielerDerDranIst = bspielerDerDranIst;     
                
            int anzahlDurchlaeufe = karten[spielerDerDranIst].Count;
              for (int i = 0; i < anzahlDurchlaeufe; i++)
                {          
                    try
                    {
                        knoten.Nodes.Add(karten[spielerDerDranIst][i].name);
                        stich.Add(karten[spielerDerDranIst][i]);

                        if (stich.Count == 3)
                        {
                            stich.RemoveRange(0, 3);
                        }                   
  
                        List<Karte> a0 = new List<Karte>(karten[0]);
                        List<Karte> a1 = new List<Karte>(karten[1]);
                        List<Karte> a2 = new List<Karte>(karten[2]);
                        List<List<Karte>> kopiekarten = new List<List<Karte>>();
                        kopiekarten.Add(a0);
                        kopiekarten.Add(a1);
                        kopiekarten.Add(a2);
                        kopiekarten[spielerDerDranIst].RemoveAt(i);
                        spielerDerDranIst++;
                        if (spielerDerDranIst == 3)
                        {
                            spielerDerDranIst = 0;
                        }
                        hinzufuegen(knoten.Nodes[i], kopiekarten, stich, spielerDerDranIst, 0);
                    }
                    catch (ArgumentOutOfRangeException)
                    {
                        textBox1.Text += "Exception! \r\n";
                    }

                }
            



        }

In meinem Fall sind in Karten immer 2 Karten drin, die ersten 6 durchläufe funktionieren auch fehlerfrei.

Viele Grüße,
Daniel

B
bloody_fighter Themenstarter:in
54 Beiträge seit 2008
vor 12 Jahren

Hier das ganze nochmal auf das nötigste reduziert:

        private void hinzufuegen2(List<List<Karte>> karten, int bspielerDerDranIst)
        {
            
            int spielerDerDranIst = bspielerDerDranIst;
            int anzahlDurchlaeufe = karten[spielerDerDranIst].Count;
            for (int i = 0; i < anzahlDurchlaeufe; i++)
            {
                List<Karte> a0 = new List<Karte>(karten[0]);
                List<Karte> a1 = new List<Karte>(karten[1]);
                List<Karte> a2 = new List<Karte>(karten[2]);
                List<List<Karte>> kopiekarten = new List<List<Karte>>();
                kopiekarten.Add(a0);
                kopiekarten.Add(a1);
                kopiekarten.Add(a2);
                kopiekarten[spielerDerDranIst].RemoveAt(i);
                spielerDerDranIst++;
                if (spielerDerDranIst == 3)
                {
                    spielerDerDranIst = 0;
                }

                hinzufuegen2(kopiekarten,  spielerDerDranIst);          

            }
        }

karten enthält also 3 Listen vom Typ List<Karte>. Jede dieser Listen repräsentiert die Karten, die der jeweilige Spieler auf der Hand hat. Die funktion soll alle verlaufsmöglichkeiten durchgehen(und dann in einem Treeview anzeigen).

1.552 Beiträge seit 2010
vor 12 Jahren

Hallo,

das Problem liegt sicherlich indirekt oder direkt am RemoveAt();
Ich warne dich: So wie du deine Rekursion benutzt findest du dich sehr schnell in einer Endlos-Rekursion wieder. Auf den ersten Blick ist die Abbruchbedingung nicht ersichtlich. Ich denke dieses Problem dürfte sicherlich auch ohne Rekursion lösbar sein. Wenn es irgendwie geht vermeide Rekursionen.

Gruß
Michael

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

B
bloody_fighter Themenstarter:in
54 Beiträge seit 2008
vor 12 Jahren

das Problem ist auf lange sicht nicht ohne Rekursion lösbar, da die Listen ja auch noch größer werden und da später dann auch noch ein Algorithmus ( Alpha Beta) darauf läuft..
Zu der Abbruchbedingung:
Am anfang hatte ich noch über dem ganzen die Abfrage:
if (karten[spielerDerDranIst].Count > 0)
Das hat aber am Inhalt nichts geändert, da die Schleife das ja quasi auch abfrägt.
Wäre cool wenn sich das jemand mal genauer anschauen könnte, habe jetzt schon viel Zeit damit verbracht, finde den Fehler aber einfach nicht..:(

1.552 Beiträge seit 2010
vor 12 Jahren

Wenn du uns genauer sagst in welcher Zeile der Fehler geworfen wird, können wir dir sicherlich besser weiterhelfen.

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

B
bloody_fighter Themenstarter:in
54 Beiträge seit 2008
vor 12 Jahren

in dem unteren Codebeispiel in:
kopiekarten[spielerDerDranIst].RemoveAt(i);
Gibt ne ArgumentOutOfRangeException

3.170 Beiträge seit 2006
vor 12 Jahren

Hallo,

wenn ich richtig blicke bricht die Rekursion erst ab wenn die for-Schleife nicht mehr durchlaufen wird weil karten[spielerDerDranIst].Count == 0 und damit eine der Listen leer ist. Dann geht's in der Rekusion wieder nach oben.
Drumherum laufen dann in jeder Rekursionsstufe noch die for-Schleifen und da ist i, das ja immer größer wird, irgendwann größer als die Anzahl der verbliebenen Karten in den Listen. Daher fliegt dann die Exception.

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

B
bloody_fighter Themenstarter:in
54 Beiträge seit 2008
vor 12 Jahren

ich verstehe nicht ganz, was das ja bedeutet..da ich die Listen ja jedes mal kopiere, bevor ich sie übergebe, darf das i doch eigentlich nicht größer werden?

49.485 Beiträge seit 2005
vor 12 Jahren

Hallo bloody_fighter,

im Debugger kannst du dir sowohl den Wert von i als auch die Länge der Liste anschauen. Damit hast du alles, was du brauchst, um den Fehler zu lokalisieren und ihn zu beheben. Eine ArgumentOutOfRangeException ist nun wirklich simpel und klar, egal ob es um eine rekursive Methode handelt oder nicht. Solche Fehler solltest du wirklich selbst in den Griff bekommen.

Eine ArgumentOutOfRangeException lässt sich auch immer durch eine vorgeschaltete Abfrage verhindern. Ob die Methode ansonsten tut, was sie soll, steht auf einem anderen Blatt. Aber auch das solltest du du wirklich selbst in den Griff bekommen.

herbivore

B
bloody_fighter Themenstarter:in
54 Beiträge seit 2008
vor 12 Jahren

Ja, das dachte ich auch, ich habe es aber nicht hinbekommen..ich habe auch lange alle möglichen Variablen mitgeloggt und versucht, das dann im nachhinein zu analysieren, bin aber zu keinem Ergebnis gekommen..an sich sollte das ganze ja tatsächlich kein Problem sein, den MinMax Algorithmus ( "Vorversion" von AlphaBeta) habe ich schon mal implementiert mit dem gleichen Rekursionsaufbau, nur dass es damals funktioniert hat. Wäre also sehr erfreut, wenn mir jemand auf die Sprünge helfen könnte. Was ich nicht verstehe ist, wieso er eine ArgumentOutOfRangeException bringt, wenn oben in der forschleife die Bedingung dafür, dass er überhaupt in die forschleife geht, ist, dass die Anzahl eben größer als 0 ist und das i dürfte ja auch nicht größergleich werden als die Anzahl in der entsprechenden Liste..

1.552 Beiträge seit 2010
vor 12 Jahren

im Debugger kannst du dir sowohl den Wert von i als auch die Länge der Liste anschauen.

Bitte verwende auch den Debugger.


for (int i = 0; i < anzahlDurchlaeufe; i++)
{
    kopiekarten[spielerDerDranIst].RemoveAt(i);
}

Anfangsliste: [1,2,3,4,5]
i = 0, RemoveAt(0) [1,2,3,4,5]
Zwischenliste: [2,3,4,5]
i = 1, RemoveAt(1) [2,3,4,5]
Zwischenliste: [4,5]
i = 2, RemoveAt(2)Liste [4,5] (element 2 nicht vorhanden

ArgumentOutOfRangeException

edit: Meistens ist dies das Problem, dass du dir die Liste änderst.

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

B
bloody_fighter Themenstarter:in
54 Beiträge seit 2008
vor 12 Jahren

aber ich entferne es doch in der kopierten liste?

1.552 Beiträge seit 2010
vor 12 Jahren

aber ich entferne es doch in der kopierten liste?

Du hast keine kopierte Liste.

  
List<Karte> a0 = new List<Karte>(karten[0]);  
List<Karte> a1 = new List<Karte>(karten[1]);  
List<Karte> a2 = new List<Karte>(karten[2]);  
List<List<Karte>> kopiekarten = new List<List<Karte>>();  
kopiekarten.Add(a0);  
kopiekarten.Add(a1);  
kopiekarten.Add(a2);  
kopiekarten[spielerDerDranIst].RemoveAt(i);  
  

Wenn spielerDerDranIst 1 ist entfernst du ein Element von a1. Durch Benutzen des Debuggerst sollte dir das aufgefallen sein.

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

B
bloody_fighter Themenstarter:in
54 Beiträge seit 2008
vor 12 Jahren

Okay, ich habe endlich den Fehler gefunden. Ich ändere ja die Variable spielerDerDranIst in jedem Schleifendruchlauf, anstatt nur die geänderte Variable zu übergeben X(
Vielen dank für eure Hilfe!