Frage von maison8, 73

Mehrere Buttons in einer If-Abfrage abfragen?

Hallo,

Ich bin gerade dran, ein TicTaeToe Spiel zu programmieren. Ich wollte gerade die Gewinnmöglichkeiten programmieren, z.B. wenn X in Button 1, 4 und 7 als Text ist, dann hat X gewonnen. Diese 3 Buttons wollte ich in einer If-Abfrage abfragen, doch egal welches Zeichen ich einsetze, ich kann die ersten beiden nie miteinander gleich abfragen. Könntet ihr mir dabei helfen? Mein Code:


Public Sub Gewinner()
    
If Button1 & Button4 & Button7.Text = "X" Then ...
Antwort
von karajan9, 48

Ich bin kein Visual Basic Experte, aber in den meisten Programmiersprachen funktioniert das so:

If Button1.Text = "X" & Button4.Text = "X" & Button7.Text = "X" Then

Vielleicht ein Versuch wert :-)

Antwort
von Manleitner, 50

Musst du vllt statt dem & ein && machen :D? Nur ne idee :)

Kommentar von maison8 ,

Dankeschön vielmals, allerdings funktioniert ihr Vorschlag leider nicht^^ Trotzdem Dankeschön :)

Kommentar von Manleitner ,

Ok schade :/ aber du wirst schon noch den richtigen Lösungsweg finden :)

Kommentar von Orsovai ,

VB benutzt für das logische und das reservierte Wort And

Antwort
von Dory1, 47

Ich kenne mich mit VB zwar nicht aus, aber ich denke mal es muss so lauten:

If Button1.Text = "X" & Button4.Text = "X" & Button7.Text = "X" Then
Antwort
von maison8, 35

Also, ich bin zur einer Lösung gekommen, falls ebenfalls andere Probleme damit bekommen sollten. Die besten waren von Dory1 und karajan9:

If Button1.Text = "X" & Button4.Text = "X" & Button7.Text = "X" Then


Visual Studio hat das nicht mehr als Fehler gekennzeichnet. Ich habe dann das "Spiel" ausgeführt, dann hat aber Visual Studio einen Ausnahmefehler bekommen, was bei weiterem debuggen anhielt. Ich habe anschließend das "&" jeweils als "And" ersetzt:

If Button1.Text = "X" And Button4.Text = "X" And Button7.Text = "X" Then

und damit war der Ausnahmefehler behoben.


Kommentar von karajan9 ,

Tatsache, der &-Operator ist bei VB scheinbar für was anders gut ;-)

https://msdn.microsoft.com/en-us/library/wfx50zyk.aspx

Kommentar von MarkusGenervt ,

Alternativ/kürzer wäre auch folgendes möglich:
Die Klammern sollen nur die Reihenfolge der Auswertung verdeutlichen und können – müssen aber nicht – gesetzt werden.
Das "&" verbindet Zeichenketten und wird vorrangig ausgewertet.

If ((Button1.Text & Button4.Text & Button7.Text) = "XXX") Then
Kommentar von CrystalixXx ,

Das ist vielleicht kürzer, aber bei weitem nicht besser oder sinnvoller.

Für diese Art und Weise müsste sichergestellt werden, dass der Text des Buttons tatsächlich nur ein (druckbares) Zeichen enthalten kann. Ansonsten könnte bei Button1.Text mit "XX" und Button4.Text mit "X" ebenfalls true ergeben, wenn Button7.Text leer ist. Mit Whitespace-Zeichen wird das ganze noch aufregender.

Obendrein sind Zeichenkettenverkettungen langsamer als das Auswerten von Boolean-Ausdrücken.

Kommentar von MarkusGenervt ,

Für das 1-Zeichen-Problem habe ich jetzt mal voraus gesetzt, dass MaxLength in allen TextBoxen auf 1 gesetzt wird. Alles Andere wäre doch ein wenig kurz gedacht.

Außerdem trifft der Boolean-Vergleich nicht zu, da bei den anderen vorgestellten Beispielen ein dreifacher Zeichenketten-Vergleich durchgeführt wird und kein BitFlag-Vergleich. Dieser kommt erst in den nächsten 2 Schritten. Somit ist es mit dem Geschwindigkeits-Vorteil eher umgekehrt.

Kommentar von CrystalixXx ,

Das Problem ist nicht der Vergleich, sondern die Verkettung von Strings.

Ich habe folgende 3 Methoden auf ihre Durchlaufzeit getestet:

Public Sub PerformanceTest1(maxCount As Integer)
For i As Integer = 0 To maxCount
If Button1.Text = "X" And Button2.Text = "X" And Button3.Text = "X" Then
End If
Next
End Sub

Public Sub PerformanceTest2(maxCount As Integer)
For i As Integer = 0 To maxCount
If ((Button1.Text & Button2.Text & Button3.Text) = "XXX") Then
End If
Next
End Sub

Public Sub PerformanceTest3(maxCount As Integer)
For i As Integer = 0 To maxCount
If Button1.Text = "X" AndAlso Button2.Text = "X" AndAlso Button3.Text = "X" Then
End If
Next
End Sub

Public Sub StartPerformanceTest()
Dim sw As New Stopwatch
sw.Start()
PerformanceTest1(100000000)
sw.Stop()
Debug.WriteLine(sw.ElapsedMilliseconds)

sw = Stopwatch.StartNew()
PerformanceTest2(100000000)
sw.Stop()
Debug.WriteLine(sw.ElapsedMilliseconds)

sw = Stopwatch.StartNew()
PerformanceTest3(100000000)
sw.Stop()
Debug.WriteLine(sw.ElapsedMilliseconds)
End Sub

Das Ergebnis (auf meiner Maschine) ist bei 3 Durchläufen eindeutig:

PerformanceTest1: 8697 ms
PerformanceTest2: 9773 ms
PerformanceTest3: 3031 ms

PerformanceTest1: 8944 ms
PerformanceTest2: 9747 ms
PerformanceTest3: 3018 ms

PerformanceTest1: 8921 ms
PerformanceTest2: 9946 ms
PerformanceTest3: 3019 ms

Vergleicht man den IL-Code von Methode 1 und 2 erkennt man die Unterschiede zwischen diesen beiden Ausführungen:

Methode 1 (Ausschnitt):

L_0008: callvirt instance class [System.Windows.Forms]System.Windows.Forms.Button TestApplication.frmTest::get_Button1()
L_000d: callvirt instance string [System.Windows.Forms]System.Windows.Forms.ButtonBase::get_Text()
L_0012: ldstr "X"
L_0017: ldc.i4.0
L_0018: call int32 [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Operators::CompareString(string, string, bool)
L_001d: ldc.i4.0
L_001e: ceq
L_0020: ldarg.0
L_0021: callvirt instance class [System.Windows.Forms]System.Windows.Forms.Button TestApplication.frmTest::get_Button2()
L_0026: callvirt instance string [System.Windows.Forms]System.Windows.Forms.ButtonBase::get_Text()
L_002b: ldstr "X"
L_0030: ldc.i4.0
L_0031: call int32 [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Operators::CompareString(string, string, bool)
L_0036: ldc.i4.0
L_0037: ceq
L_0039: and
L_003a: ldarg.0
L_003b: callvirt instance class [System.Windows.Forms]System.Windows.Forms.Button TestApplication.frmTest::get_Button3()
L_0040: callvirt instance string [System.Windows.Forms]System.Windows.Forms.ButtonBase::get_Text()
L_0045: ldstr "X"
L_004a: ldc.i4.0
L_004b: call int32 [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Operators::CompareString(string, string, bool)

Methode 2 (Ausschnitt):

L_0008: callvirt instance class [System.Windows.Forms]System.Windows.Forms.Button TestApplication.frmTest::get_Button1()
L_000d: callvirt instance string [System.Windows.Forms]System.Windows.Forms.ButtonBase::get_Text()
L_0012: ldarg.0
L_0013: callvirt instance class [System.Windows.Forms]System.Windows.Forms.Button TestApplication.frmTest::get_Button2()
L_0018: callvirt instance string [System.Windows.Forms]System.Windows.Forms.ButtonBase::get_Text()
L_001d: ldarg.0
L_001e: callvirt instance class [System.Windows.Forms]System.Windows.Forms.Button TestApplication.frmTest::get_Button3()
L_0023: callvirt instance string [System.Windows.Forms]System.Windows.Forms.ButtonBase::get_Text()
L_0028: call string [mscorlib]System.String::Concat(string, string, string)
L_002d: ldstr "XXX"
L_0032: ldc.i4.0
L_0033: call int32 [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Operators::CompareString(string, string, bool)

Ein Vergleich von Zeichenketten erfolgt in beiden Methoden, allerdings wird in Methode 2 die Concat-Methode der String-Klasse aufgerufen. Und genau dort findet der "Performance-Einbruch" statt. (Man könnte jetzt noch in die Methode reinschauen, aber wäre etwas zu viel jetzt). Jedenfalls wird dort neuer Speicher reserviert. Anschließend werden die Zeichenketten einzeln dort hinein kopiert. Genau diese Schritte sind es, die deutlich langsamer als ein "simpler" Vergleich ausgeführt werden.

Bei Methode 3 übrigens, wo AndAlso verwendet wird, wurde im Test nach dem ersten Vergleich abgebrochen, weil das Resultat False ergab. Im "Fehlerfall" ist AndAlso deutlich besser.

Kommentar von CrystalixXx ,

Anstatt von And könntest du auch AndAlso verwenden. Das hat den Vorteil, dass nicht alle Ausdruckspaare ausgewertet werden, sobald ein Ausdruck False ergibt.

Würde also Button1.Text kein X sein, würden mit "And" Button4.Text und Button7.Text dennoch geprüft werden, obwohl das Gesamtergebnis niemals True sein kann. Bei AndAlso würde in diesem Fall das Ergebnis direkt False sein und Button4.Text und Button7.Text nicht mehr geprüft werden.

Keine passende Antwort gefunden?

Fragen Sie die Community