ForEach durchläuft nicht alle Einträge Logikproblem?

  • VB.NET
  • .NET (FX) 3.0–3.5

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von sonne75.

    ForEach durchläuft nicht alle Einträge Logikproblem?

    Hallo,

    ich erstelle gerade ein kleines TicTacToe-Spiel.
    Ich möchte dieses Skalierbar anbieten, d.h. man soll nicht nur 3x3 Spielfelder spielen können sondern auch 4x4, 5x5....

    Ich steh gerade vor einem kleine Problem beim Skalieren.

    Ich vergebe von Links nach Rechts und Von Oben Nach unten jeden Feld eine Nummer.
    Wenn ich die Spielfeldgröße ändere muss ich jeden Button eine neue Nummer vergeben.
    Das funktioniert soweit auch super und ohne Probleme.

    Probleme gibt es aber den Punkt, wenn ich die Spielfeldgröße runterskaliere und Buttons zu viel da sind.
    Diese Lösche ich dann mit einer ForEach-Schleife, wobei ich Prüfe ob der Button noch in der Feldgröße liegt.
    Wenn also z.B. ein 3x3 Feld vorliegt, werden alle Buttons welche in Spalte oder Zeile größer 3 liegen, z.B. 4, gelöscht.

    Nun das Problem: Es werden nicht alle Buttons gelöscht. Und nur deswegen, weil sie nicht mit der ForEach durchlaufen werden. So ganz verstehen tue ich das nicht, weil ich teoretisch jeden Button im gleichen Panel erstelle. Und manche Buttons dann doch nicht durchlaufen werden.

    Naja schaut selbst.
    Hier ein auf das Problem gekürzter Quelltext. Buttons erstelle ich alle im Code, ihr müsst nur den Code ausführen.

    Quellcode

    1. Public Class Form1
    2. Dim l As Integer
    3. Dim Field(5, 5) As Button
    4. Dim Button(3) As RadioButton
    5. Dim Panel1 As New Panel
    6. Function ToX(ByVal Num As Integer, ByVal level As Integer) As Integer
    7. Return Num Mod level + 1
    8. End Function
    9. Function ToY(ByVal Num As Integer, ByVal level As Integer) As Integer
    10. Return ((Num - ToX(Num, level) + 1) / level) + 1
    11. End Function
    12. Function ToNum(ByVal X As Integer, ByVal Y As Integer, ByVal level As Integer) As Integer
    13. Return X + (level * (Y - 1)) - 1 'Nullbasiert
    14. End Function
    15. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Controls initialisieren
    16. Me.Size = New Size(600, 600)
    17. For i = 3 To 5
    18. Button(i - 2) = New RadioButton
    19. With Button(i - 2)
    20. .Location = New Point(52 + (100 * (i - 3)), 10)
    21. .Size = New Size(98, 25)
    22. .Text = Str(i) + " x " + Str(i)
    23. AddHandler .Click, AddressOf Button_Click
    24. End With
    25. Button(1).Checked = True
    26. Me.Controls.Add(Button(i - 2))
    27. Next
    28. With Panel1
    29. .Location = New Point(50, 50)
    30. .Size = New Size(500, 500)
    31. End With
    32. Me.Controls.Add(Panel1)
    33. End Sub
    34. Private Sub Button_Click(ByVal sender As RadioButton, ByVal e As System.EventArgs)
    35. For Each i As RadioButton In Me.Controls.OfType(Of RadioButton)()
    36. If sender Is Button(1) Then
    37. InitButtons(3)
    38. ElseIf sender Is Button(2) Then
    39. InitButtons(4)
    40. ElseIf sender Is Button(3) Then
    41. InitButtons(5)
    42. End If
    43. Next
    44. End Sub
    45. Function InitButtons(ByVal size As Integer) As Boolean
    46. If size <> l Then
    47. For Each i As Control In Panel1.Controls.OfType(Of Button)() 'In Field?
    48. If TypeOf i Is Button Then
    49. If (ToX(i.TabIndex, l) > size) Or (ToY(i.TabIndex, l) > size) Then 'überflüssige Buttons entfernen
    50. MessageBox.Show("Button " + Str(i.TabIndex) + " wurde gelöscht") '+ ((ToY(i.TabIndex, l) - 1) * (size - l))
    51. Panel1.Controls.Remove(i)
    52. Else 'existierende Buttons neu durchnummerieren
    53. MessageBox.Show("Button " + Str(i.TabIndex) + " bleibt erhalten")
    54. i.TabIndex += ((ToY(i.TabIndex, l) - 1) * (size - l))
    55. Field(ToX(i.TabIndex, size), ToY(i.TabIndex, size)) = i
    56. i.Text = Str(i.TabIndex)
    57. End If
    58. End If
    59. Next
    60. For i = 0 To size ^ 2 - 1
    61. If (ToX(i, size) > l) Or (ToY(i, size) > l) Then 'Fehlende Buttons erstellen
    62. Field(ToX(i, size), ToY(i, size)) = New Button
    63. MessageBox.Show("Button " + Str(i) + " wurde erstellt")
    64. With Field(ToX(i, size), ToY(i, size))
    65. .Location = New Point(100 * (ToX(i, size) - 1) + 2, 100 * (ToY(i, size) - 1) + 2)
    66. .Size = New Size(98, 98)
    67. .TabStop = True
    68. .TabIndex = i
    69. .Text = Str(i)
    70. End With
    71. Panel1.Controls.Add(Field(ToX(i, size), ToY(i, size)))
    72. End If
    73. Next
    74. l = size
    75. End If
    76. End Function
    77. End Class


    Ich hoffe ihr könnt irgendwie helfen.

    LG

    Julian


    Nachtrag: Achso, anfangs habe ich immer alle Buttons gelöscht und alle Buttons wiedererstellt. Das hat zwar funktioniert, aber hat zu viel geflaktert.
    VB-Code-Tags bitte (rechts im Editor auf VB.NET klicken). Dass Controls für Spiele nicht besonders sinnvoll sind, lasse ich außen vor.

    Wenn du die Controls löschst, sägst du am Ast ab, auf dem du sitzt. Deswegen solltest du beim Löschen immer rückwärts gehen:

    VB.NET-Quellcode

    1. Dim buttons=Panel1.Controls.OfType(Of Button)
    2. For i=buttons.Count-1 To 0 Step -1 'oder .Length, kann es mir nie merken, was wo
    3. .....
    4. Panel1.Controls.Remove(buttons(i)
    5. Next
    wundert mich, dasses keine Exception gibt - in ForEach kann man nicht löschen.

    Denk mal eine Liste mit 10 Items, und ForEach steht auf dem 5. Item, und löscht es.
    Dann rücken die folgenden Items eine Stelle nach vorn, weil die Liste hat nun nur noch 9 Items.
    Das weiß aber das For Each nicht, und deshalb wird es beim nächsten Next das in Wirklichkeit übernächste Item adressieren. 8|

    sonne75 schrieb:

    VB-Code-Tags bitte (rechts im Editor auf VB.NET klicken). Dass Controls für Spiele nicht besonders sinnvoll sind, lasse ich außen vor.

    Wenn du die Controls löschst, sägst du am Ast ab, auf dem du sitzt. Deswegen solltest du beim Löschen immer rückwärts gehen:

    VB.NET-Quellcode

    1. Dim buttons=Panel1.Controls.OfType(Of Button)
    2. For i=buttons.Count-1 To 0 Step -1 'oder .Length, kann es mir nie merken, was wo
    3. .....
    4. Panel1.Controls.Remove(buttons(i)
    5. Next


    Danke das hat geholfen.

    Ich versteht leider immer noch nicht genau wieso es vorher nicht funktioniert hat.

    Kannst dus noch mal besser erklären?
    Wenn du aus einer Auflistung etwas entfernst, dann kann For Each nicht mehr richtig den Index ermitteln, weil die Auflistung sich durch das Löschen verändert hat.

    Wenn du rückwärts gehst, löschst du immer nur das letzte Element, d.h. die restlichen Elemente behalten ihren Index, bis sie gelöscht werden.