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
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).
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
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..:(
in dem unteren Codebeispiel in:
kopiekarten[spielerDerDranIst].RemoveAt(i);
Gibt ne ArgumentOutOfRangeException
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
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?
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
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..
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.
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.
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!