my compare statement not working in vb.net - vb.net

I was doing an exam algorithm earlier (Just started vb 5 days ago so be nice ;) ) and I realised after testing that for whatever reason my statement If 0 < CInt(Num(x)) < 10 was not working which completely baffled me as I would thinkk that of all things THIS would be the easiest but no. No matter what I did, it just would always be true even if I made Num(X) = 90 or 9000000 it wouldn't matter, so if anyone knows what obvious mistake I have made whether its because I made it a string or what let me know :)
Dim Num(2), INPUT As String
Dim Cond As Boolean = False
Dim Valid As Boolean = False
Dim Isnum As Boolean
Dim x, Number, IsTen As Integer
While Cond = False
Do Until IsTen = 3 And Number = 3
IsTen = 0
Number = 0
For x = 0 To 2
MsgBox("Please enter a number")
Num(x) = (Console.ReadLine)
Isnum = IsNumeric(Num(x))
If Isnum = True Then
IsTen = IsTen + 1
End If
If Isnum = True Then
If 0 < CInt(Num(x)) < 10 Then
Number = Number + 1
End If
End If
Next
If Number <> 3 Then
MsgBox("Sorry all three numbers werent between 0 and 10, Please enter again")
End If
If IsTen <> 3 Then
MsgBox("Sorry all three inputs werent numbers, Please enter again")
End If
Loop
MsgBox("All three numbers are valid")
End While

First thing I would advise is setting Option Strict On at the top of your code file. You can also make this the default via Visual Studio options. This will warn you about the implicit type conversion that is causing your problem.
Changing the line
If 0 < CInt(Num(x)) < 10 Then
I'm assuming the intent here is to ensure the number is greater than 1 but less than 10
To something like this:
If Isnum = True Then
Dim val As Integer = Integer.Parse(Num(x))
If (val > 0) AndAlso (val < 10) Then
Number = Number + 1
End If
End If
Notice the use of Integer.Parse() to type cast the string to Int, it's a little more robust but there is also the Integer.TryParse() which is another step up again, might be worth reading up on. Also notice AndAlso usage, this is a short circuit operator so if the First condition is false, doesn't bother evaluating the next.

Related

Visual Basic dividing

I'm on visual basic and I'm reading through some piece of code my teacher wrote, he had this chunck of code:
Private Sub btnDividing_Click(sender As Object, e As EventArgs) Handles btnDividing.Click
Dim number As Integer = InputBox("Divide number by 2:")
Dim result As Integer = 0
Do While (number <> 0)
result += 1
number = number - 2
Loop
MsgBox("The result is: " & result, MsgBoxStyle.Exclamation)
End Sub
So my teacher typed the result += 1 and number = number -2 I didn't really understand that part so i tried simplifying it by changing it to:
Dim number As Integer = InputBox("Divide number by 2:")
Dim result As Integer = 0
Do While (number <> 0)
result = number / 2
Loop
MsgBox("The result is: " & result, MsgBoxStyle.Exclamation)
End Sub
but it keeps freezing after I click "OK"
Any suggestions?
It freezes because you made it an infinite loop:
Do While (number <> 0)
result = number / 2
Loop
The loop checks the value of number, but your modified code in the loop never modifies the value of number. So if the condition is true the first time it's checked, it will always be true. The original code modified the value:
Do While (number <> 0)
result += 1
number = number - 2
Loop
Since number is decremented by 2 with each iteration of the loop, it will eventually (assuming it's even) be equal to 0, making the loop condition false and the loop will end.
Basically, a loop needs to in some way modify the values being checked in the condition (or have some other control statement to exit the loop) or the loop will infinitely run.

What is wrong with this vb wfa code?

What is wrong with this code for multiple checkboxes in vb wfa, it says it can't be converted to a boolean:
If ch1.Checked & ch2.Checked = True Then
score = score + 1
End If
In vb, the operator is And:
If (ch1.Checked And ch2.Checked) Then
score = score + 1
End If
If you want compare that both checkboxes are checked then AndAlso will be little bid better, because it will not evaluate second checkbox value if first is false
If ch1.Checked AndAlso ch2.Checked Then
score = score + 1
End If
In c# it is same as && operator

How to enable/disable button with a function

I have a problem with my university project
It's a little game, 6 buttons for each players and 2 players so 12 buttons
There is number in each buttons, if a player has his 6 buttons at 0, he can't play
I have try some Public Function and i'm actually working with a very simple one but i think this is not the problem
My function is here
And in my form, the problem is here, i've tried many things but i don't know how do to that ... I read my lesson and I'm searching on the internet, i have no idea ..
If possible is True you don't re-enable the button.
You can simplify things.
Public Function PeutJouer(ByVal joueur As Integer) As Boolean
Dim sum As Integer
Dim start As Integer = (joueur - 1) * 7
For i As Integer = start To start + 5
sum += tableau(i)
Next
Return sum <> 0
End Function
Then
Btn1P1.Enabled = PeutJouer(1)
Did you show all the relevant code? You are declaring Dim tableau(12) As Integer but the array is never filled with values. Probably tableau should be declared at the form level and not locally in this function. If you already have both, remove the local declaration, because it hides the one at form level. You also need to return the result from the function. I don't see this in your function.
Note that this
If x <> 0 Then
booleanVariable = True
Else
booleanVariable = True
End If
can be simplified to
booleanVariable = x <> 0
i.e., the condition is an expression yielding the Boolean result True or False already and you can use this value directly. When working with numeric values you don't write If x + y = 1 Then r = 1 Else If x + y = 2 Then r = 2 .... You simply write r = x + y.

Sorting List(Of T) stopping early

I have a custom class called SaveFile. One property it has is SaveNumber and I'm trying to sort the list by that property. I read a bunch of articles here and got it to sort properly but it's stopping early? The case in which I noticed this is with set that has 79 saves. It would sort: 1, 2, 3, 4, 5, 6, 7, 10, 11, ... 30, 8, 31, ... 70, 9, 71, .. The code I use is
saveList.Sort(Function(x, y) x.CompareTo(y))
But if I use the code:
For i = 0 To 3
saveList.Sort(Function(x, y) x.CompareTo(y))
Next
then it sorts right but it takes a very long time and one set has over 700 SaveFiles in it so it takes almost 5 minutes for my program to load. Any ideas?
This is the code that I have for my CompareTo function:
Public Function CompareTo(y As SaveFile) As Integer Implements IComparable(Of SaveFile).CompareTo
'If neither are an autosave then compare save number
If Not Me.Text.StartsWith("autosave") And Not y.Text.StartsWith("autosave") Then
If Me.SaveNumber.ToString.Length > y.SaveNumber.ToString.Length Then
Return False
ElseIf Me.SaveNumber.ToString.Length < y.SaveNumber.ToString.Length Then
Return True
End If
Return Me.SaveNumber < y.SaveNumber
'if either is an autosave
Else
'Create to comparable integers with
'a value of 4. We set the value to
'4 because it is higher than the 3
'available autosaves, making it sort
'after any autosaves if only one is
'an autosave.
Dim xComp As Integer = 4
Dim yComp As Integer = 4
'If x is an autosave then figure out
'which autosave number it is.
If Me.Text.StartsWith("autosave") Then
Select Case True
Case Me.Text.EndsWith("1")
xComp = 1
Case Me.Text.EndsWith("2")
xComp = 2
Case Me.Text.EndsWith("3")
xComp = 3
End Select
End If
'if y is an autosave then figure out
'which autosave number it Is.
If y.Text.StartsWith("autosave") Then
Select Case True
Case y.Text.EndsWith("1")
yComp = 1
Case y.Text.EndsWith("2")
yComp = 2
Case y.Text.EndsWith("3")
yComp = 3
End Select
End If
Return xComp < yComp
End If
End Function
First, asking 2 questions in one post is not a good idea because it reduces the chances someone will know the answer to both. For example, without seeing the code that loads these things or even what they are, makes it just a guess why it takes so long to load.
For the sorting, your CompareTo method is flawed. From MSDN:
Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object.
That is, it should return -1 (precedes), 1 (follows) or 0 (same). Yours just returns Boolean:
If Me.SaveNumber.ToString.Length > y.SaveNumber.ToString.Length Then
Return False
ElseIf Me.SaveNumber.ToString.Length < y.SaveNumber.ToString.Length Then
Return True
End If
...
Return xComp < yComp
We have no idea what type SaveNumber is, but if it is am integer, comparing the length of the string form if it is not the same as comparing the value:
' Me vs Other
Return "9".Length < "7".Length
That will return False (0) when it by value, it should return 1. Turning on Option Strict would have flagged the incorrect return type, which might have led you to the answer. It should be something like this, ignoring the "auto" logic:
Public Function CompareTo(other As SaveItem) As Integer _
Implements IComparable(Of SaveItem).CompareTo
... special handling for "auto"
If Me.SaveNumber = other.SaveNumber Then
Return 0
ElseIf Me.SaveNumber < other.SaveNumber Then
Return -1
Else
Return 1
End If
End Function
But, you may not even need that (assuming again that SaveNumber is an int):
saveItems = saveItems.OrderBy(Function(q) q.SaveNumber).ToList()
IComparable.CompareTo() might be needed in order to handle the "autosave" logic but it might be able to be handled in the OrderBy() depending on the information the class exposes.

How to not generate a stack overflow when a sub procedure calls itself?

This code generates a stack overflow. I'm aware it is caused by the procedure calling itself.
What can I do to avoid the stack overflow? Recalling the sub procedure and generating a new random number is the easiest thing to do, however it generates the overflow. The randomly generated number picks a random inventory item, then the if statement matches that number (random inventory item) with the quantity of that item from the deck inventory to make sure it isn't less than 1. If the inventory of that item is 0, the else plays and restarts the procedure, generating a new random number and doing the process all over again. In another procedure I have a function that if the deck's inventory becomes completely empty, then the discard pile replenishes the deck, making the discard pile empty, so there should never be a case where all randomly generated numbers can be associated item with a inventory of 0.
I wonder if I could somehow force the random number generator
Number = (DeckGroup(Rnd.Next(0, DeckGroup.Count)).ID)
not to generate numbers to inventory items DeckGroup(Number).QuantityInteger that are zero. By doing so I wouldn't even need to recall the function.
The random number is generated by a different branch in the same structure group.
Private Sub PlayElse()
Dim CardCheckBoxArray() As CheckBox = {CardCheckBox1, CardCheckBox2, CardCheckBox3, CardCheckBox4, CardCheckBox5}
'Reset Number Generator
Number = (DeckGroup(Rnd.Next(0, DeckGroup.Count)).ID)
Dim PlayerQuantitySubtractionInteger As Integer
For PlayerQuantitySubtractionInteger = ChecksDynamicA To ChecksDynamicB
If CardCheckBoxArray(TextBoxInteger).Checked = True And DeckGroup(Number).QuantityInteger > 0 Then
DeckGroup(Number).QuantityInteger -= 1
'Select the Player depending value of T
Select Case T
Case 0
Player1HandGroup(Number).QuantityInteger += 1
Case 1
Player1HandGroup(Number).QuantityInteger2 += 1
Case 2
Player1HandGroup(Number).QuantityInteger3 += 1
Case 3
Player1HandGroup(Number).QuantityInteger4 += 1
Case 4
Player1HandGroup(Number).QuantityInteger5 += 1
End Select
CardTypeArray(PlayerQuantitySubtractionInteger) = Player1HandGroup(Number).CardType
CardCheckBoxArray(TextBoxInteger).Text = Player1HandGroup(Number).CardNameString
NumberArray(PlayerQuantitySubtractionInteger) = Number
Else
If CardCheckBoxArray(TextBoxInteger).Checked = True And DeckGroup(Number).QuantityInteger < 0 Then
Call PlayElse()
End If
End If
Next PlayerQuantitySubtractionInteger
End Sub
You could use LINQ to weed out all the objects you never want to get first and then use the collection returned by the linq instead of your original collection.
Something like:
Private Sub PlayElse()
Dim CardCheckBoxArray() As CheckBox = {CardCheckBox1, CardCheckBox2, CardCheckBox3, CardCheckBox4, CardCheckBox5}
'Reset Number Generator
Dim temp As IEnumerable(Of LunchMoneyGame.LunchMoneyMainForm.Group) = From r In DeckGroup Where r.QuantityInteger > 0 Select r
If temp IsNot Nothing AndAlso temp.Any Then
Number = (temp(Rnd.Next(0, temp.Count)).ID)
' ** Edit **: This will ensure that you only got 1 object back from the LINQ which can tell you whether or not you have bad data. You *can* exclude this check but its good practice to include it.
Dim obj As LunchMoneyGame.LunchMoneyMainForm.Group = Nothing
Dim t = From r In temp Where r.ID = Number Select r
If t IsNot Nothing AndAlso t.Count = 1 Then
obj = t(0)
End If
If obj IsNot Nothing Then
Dim PlayerQuantitySubtractionInteger As Integer
For PlayerQuantitySubtractionInteger = ChecksDynamicA To ChecksDynamicB
' ** Edit **
obj.QuantityInteger -= 1
'Select the Player depending value of T
Select Case T
Case 0
Player1HandGroup(Number).QuantityInteger += 1
Case 1
Player1HandGroup(Number).QuantityInteger2 += 1
Case 2
Player1HandGroup(Number).QuantityInteger3 += 1
Case 3
Player1HandGroup(Number).QuantityInteger4 += 1
Case 4
Player1HandGroup(Number).QuantityInteger5 += 1
End Select
CardTypeArray(PlayerQuantitySubtractionInteger) = Player1HandGroup(Number).CardType
CardCheckBoxArray(TextBoxInteger).Text = Player1HandGroup(Number).CardNameString
NumberArray(PlayerQuantitySubtractionInteger) = Number
Next PlayerQuantitySubtractionInteger
End If
End If
End Sub
Pass through the list and determine only those that are valid. Then randomly pull from that set. Here is a simple version of it. You could use LINQ as well, but this should be clear enough:
Dim validDeckGroupsIndexes As New List(Of Integer)
For ndx As Integer = 0 to DeckGroup.Count - 1
If DeckGroup(ndx).QuantityInteger > 0 Then
validDeckGroupsIndexes .Add(ndx)
End If
Next ndx
Then use this:
Dim deckGroupNdx As Integer = Rnd.Next(0, validDeckGroupsIndexes.Count)
Number = DeckGroup(deckGroupNdx).ID