Null Reference Exception was Unhandled - vb.net

This is a very simple code. I am just beginning to use vb. Im making a game where you reorder the shuffled numbers into the correct order. You try to solve the puzzle in the least amount of time and least amount of clicks, and the next time you play, you try to get a lower score (or beat that record). You have sixteen buttons (4x4) and fifteen numbers. There is a checkbutton function to see if the puzzle is solved Every time I debug the program, it highlights the Clicks and FinalTime and says Null Reference Exception was Unhandled. Heres some of the code.
Public Class Form1
Dim Clicks As Integer = 0 'The variable that counts the number of times you clicked
Dim Time As Integer 'The vairable that holds the time
Dim TimeMin As Integer 'The variable that holds the minutes
Dim TimeSec As Integer 'The variable that holds the seconds
Dim FinalTime As String 'The variable that holds the final time (minutes and seconds)
Dim lngArray() As String = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", ""} {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", ""}
Dim NumArray() As Integer
Dim NumArray1() As String
Private Sub CheckButton(ByRef Butt1 As Button, ByRef Butt2 As Button)
If Butt2.Text = "" Then 'Checks if the button around the clicked number is empty "" It's the location of the empty square that you want the number in Butt1 to move to.
Butt2.Text = Butt1.Text 'If it is, the value from Butt2 will "copy and paste" into Butt1
Butt1.Text = "" 'Butt1 will keep the value and the value in Butt2 will clear ""
Clicks += 1 'Incrementing Each click by only 1. It's a counter. In addition, the code above only allows the click to increment by 1 if the number has moved. If you just click on a number that can't move, the click would not count.
End If
If Clicks > 1 Then
lblTotal.Text = Clicks & " Clicks" 'Shows the total amount of clicks when it is greater than one
Else
lblTotal.Text = Clicks & " Click" 'Shows the total amount of clicks when it is one
End If
End Sub
Private Sub CheckSolved() 'A private sub that checks if the puzzle is solved ,restarts the count, and stops the time
Dim strName As String = "" 'The variable that has the string of the winners name
If Me.Button1.Text = "1" And Me.Button2.Text = "2" And Me.Button3.Text = "3" And Me.Button4.Text = "4" And Me.Button5.Text = "5" And Me.Button6.Text = "6" And Me.Button7.Text = "7" And Me.Button8.Text = "8" And Me.Button9.Text = "9" And Me.Button10.Text = "10" And Me.Button11.Text = "11" And Me.Button12.Text = "12" And Me.Button13.Text = "13" And Me.Button14.Text = "14" And Me.Button15.Text = "15" Then 'Checks if the numbers are in the correct buttons
Timer1.Enabled = False 'Stops the time
strName = InputBox("What is your name", "Name of winner") 'Get's the winners name
MessageBox.Show("In " & FinalTime & " , you solved the puzzle in " & Me.Clicks & " clicks! Congratulations " & strName) 'Messagebox showing how many times you clicked to solve the puzzle. It gets the name you typed into the inputbox (strname) and displays it
Call Restart() 'Shuffles the buttons and restarts the game when you win
Call Record(NumArray, NumArray1)
End If
End Sub
Private Sub Record(ByVal NumArray() As Integer, ByVal NumArray1() As String)
'Make timemin array and then make time array. Then make click array
For i As Integer = 0 To 1000
NumArray(i) = Clicks 'This is where the Null Reference error occured
i = +1
Array.Sort(NumArray) 'sorting the array values from least to greatest
Next i
lblRecordClicks.Text = NumArray(0) & " Clicks" 'displaying the lowest number of clicks in the label
For k As Integer = 0 To 1000 'Making an integer that captures 1000 values
NumArray1(k) = FinalTime 'This is where the Null Reference error occured
k = +1
Array.Sort(NumArray1) 'sorting the array values from least to greatest
Next k
lblRecordTime.Text = NumArray1(0) 'displaying the lowest time in the label
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Call Times()
End Sub
Private Sub Shuffle(ByVal lngArray As Object) 'Shuffles the values of the Array
Dim i As Long
Dim iMin As Long
Dim iMax As Long
Dim lngReplace As Long
Dim varSwap As Object
iMin = LBound(lngArray)
iMax = UBound(lngArray)
For i = iMax To iMin + 1 Step -1
lngReplace = Int((i - iMin + 1) * Rnd() + iMin)
varSwap = lngArray(i)
lngArray(i) = lngArray(lngReplace)
lngArray(lngReplace) = varSwap
Next
Button1.Text = lngArray(0)
Button2.Text = lngArray(1)
Button3.Text = lngArray(2)
Button4.Text = lngArray(3)
Button5.Text = lngArray(4)
Button6.Text = lngArray(5)
Button7.Text = lngArray(6)
Button8.Text = lngArray(7)
Button9.Text = lngArray(8)
Button10.Text = lngArray(9)
Button11.Text = lngArray(10)
Button12.Text = lngArray(11)
Button13.Text = lngArray(12)
Button14.Text = lngArray(13)
Button15.Text = lngArray(14)
Button16.Text = lngArray(15)
End Sub
Private Sub RestartToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RestartToolStripMenuItem.Click
Call Restart()
Call Me.btnStart_Click(sender, e) 'Call the button click to enable all buttons
End Sub
Private Sub Times()
Time = Time + 1 'Increase the time by 1 second every interval
TimeSec = TimeSec + 1 'Increase the time by 1 second every interval
TimeMin = Convert.ToInt32(TimeSec \ 60) 'Takes the whole number of the amount of seconds divided by 60 and leaves out the remainder
If Time >= 60 Then
Time = 0
End If
'If the seconds pass 59 (and they do), it restarts to 0
FinalTime = TimeMin & " min " & Time & " seconds" 'Final time is the string displayed showing the final time
lblTime.Text = FinalTime 'The label displays the final time
End Sub
Private Sub Restart()
Time = 0 'Resets the time
Clicks = 0 'Resets the amount of clicks
lblTotal.Text = "" 'Clears the label
lblCheat.Visible = False
lblTotal.Visible = True
lblClicks.Visible = True
lblQuote.Visible = True
lblRecordClicks.Visible = True
lblRecordTime.Visible = True
'If the user cheated and hit the solve button and wants to restart and solve the puzzle on their own, then he can. Turning these label settings to true allows you to see them again
Call Shuffle(lngArray) 'Shuffles the numbers
Timer1.Enabled = True 'Continues the time when it resets to 0
End Sub
Public Sub RefreshEverythingToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RefreshEverythingToolStripMenuItem.Click
Timer1.Enabled = False 'Pauses the timer
If MessageBox.Show("Do you want to restart everything?", "Restart Game", MessageBoxButtons.YesNo, MessageBoxIcon.Information) = DialogResult.Yes Then
Time = 0
TimeSec = 0
'Resets the time
Clicks = 0 'Resets the amount of clicks
lblTotal.Text = "" 'Clears the label
lblRecordClicks.Text = "" 'Resets the record click
lblRecordTime.Text = "" 'Resets the record time
End If
Call Shuffle(lngArray) 'Shuffles the numbers
Timer1.Enabled = True 'Continues the timer if no is selected
ReDim NumArray(1000) 'Clears the array data that was captured
ReDim NumArray1(1000) 'Clears the array data that was captured
End Sub
End Class
If you do decide to help (and I HOPE you do) could you try to avoid using "computer" talk and try to "dumb it down for me". Like I said before, I am new at this. Thanks for your time.

You are trying to save the values to an array. When you define an array like Dim NumArray() As Integer there are no bounds set for the array (the array is basically Nothing) and if you then try to access an array item you encounter the Null reference exception.
You only set the array bounds in Public Sub RefreshEverythingToolStripMenuItem_Click. Now I don't know all of your code but if the game is started without the user specifically clicking this button then your array will be Nothing.
You have to make sure that the array bounds are always set before a game is started.
You could also look into more abstract array-like types in .NET. For example you could try a list. A List is practically an array with arbitrary bounds. You define the List with a specific type using the Of keyword and you can then add items to it with the lists Add method, remove items, sort the list etc.
Define as a global variable:
Dim FinalTimes as New List(Of Integer)
Dim FinalClicks as New List(Of Integer)
Make sure you use the New keyword here. This means that a new object of class List will be created. Otherwise you would encounter Null Reference Exceptions on the lines below again.
When the user solves the puzzle you then do:
FinalTimes.Add(FinalTime)
FinalClicks.Add(Clicks)
FinalTimes.Sort
FinalClicks.Sort
This will basically increase the length of the list by one, write the FinalTime/Clicks value into the last item and then resort both lists. Ideas: For a highscore you might want to connect FinalTime, Clicks and Player Name into a structure and use the IComparer Interface to let the user sort the high score list by name/Time/Clicks.
Jens
PS: Before I forget: The For loops in which the exception occured in your code make no real sense. First problem is that in their current forms they would be infinite loops because you always set i to 1 in the loop while the loop ends when i=1000 (which would never happen, obviously). I think you meant i=i+1 or shorter i += 1 there. But they still make little sense. I tried it out to see what happens exactly (which is not obvious :-)) and half of your high score is overwritten by the new value etc. I think the above method will be easier. :-)

Related

How do I make my calculator accept multiple values and multiple operators before pressing the equal button?

I'm a newbie in VB.NET so I followed a tutorial. The current code only takes the first value, operator, and then the second value before I press the equal button. It's working as intended. But I want to know how to make it accept multiple values and multiple operators before I press the Equal button.
Here is the current code for the operator buttons and the equal button and the variables declared:
Dim firstval, secondval, result As Double
Dim op As String
Private Sub Operator_Click(sender As Object, e As EventArgs) Handles Button17.Click, Button16.Click, Button15.Click, Button14.Click
Dim b As Button = sender
firstval = Label1.Text
Label2.Text = Label1.Text
Label1.Text = ""
op = b.Text
Label2.Text = Label2.Text + " " + op
End Sub
Private Sub Button13_Click(sender As Object, e As EventArgs) Handles Button13.Click
secondval = Label1.Text
If op = "+" Then
result = firstval + secondval
Label1.Text = result
ElseIf op = "-" Then
result = firstval - secondval
Label1.Text = result
ElseIf op = "×" Then
result = firstval * secondval
Label1.Text = result
ElseIf op = "÷" Then
result = firstval / secondval
Label1.Text = result
If secondval = "0" Then
Label1.Text = ""
Label3.Text = "CANNOT DIVIDE BY ZERO"
End If
End If
End Sub
You could use a string to store the entire math problem the user inputs and add the number or operator to it depending on the button you click. This way you could have practically infinite amounts operators and numbers.
When the string is done you can let it calculate when the "=" button or whatever button you're using is pressed.
You would start by declaring the variable
Dim input As String
Then use this code when you click a button
input = input + NAMEOFBUTTON.text
This will make it add the content of the button to the current input. NAMEOFBUTTON would be the name of the button the code runs under.
You might need to use "/" as the button name for division.
When clicking on "=" this code should run:
Dim output = New DataTable().Compute(input, Nothing)
Then you could use a label to display the output. NAMEOFLABEL is of course the name of the label you display it on.
You might need to convert the output to a string before showing it on a label.
NAMEOFLABEL.text = output.ToString

How to exit loop with "keyword"

Here's my code:
Dim n As String, upper As String, lower As String
Label2.Text = "EXIT"
Label3.Text = "exit"
upper = Label2.Text
Label2.Text = upper.ToUpper
lower = Label3.Text
Label3.Text = lower.ToLower
Do
Label1.Text = InputBox(" Enter a word. If you would like to quit, type: EXIT in the inputbox")
n = Label1.Text
Label1.Text = n.Length
Label1.Text = Label1.Text & " letters"
Loop Until n = ""
Label1.Visible = False
MsgBox(" Invalid value!")
End
Do
Label1.Text = InputBox(" Enter a word. If you would like to quit, type: EXIT in the inputbox")
n = Label1.Text
Label1.Text = n.Length
Label1.Text = Label1.Text & " letters"
Loop Until upper = Label2.Text
Label1.Visible = False
MsgBox(" You have exited the program!")
End
Do
Label1.Text = InputBox(" Enter a word. If you would like to quit, type: EXIT in the inputbox")
n = Label1.Text
Label1.Text = n.Length
Label1.Text = Label1.Text & " letters"
Loop Until lower = Label3.Text
Label1.Visible = False
MsgBox(" You have exited the program!")
End
The issue I'm having with this program is when I run it and press the cancel button or the X button to exit, it executes correctly with the loop. But with the other 2 loops, when I type in "exit" or "EXIT" in uppercase or lowercase, it just displays how many characters are in the word instead of ending the program.
While the answer is missing, I state that the String "Label3" is not part of the InputBox String defaultValue. The "Label1" Text is used and not changed to be saved to "Label2" or "Label3".
The Do Statement seems to iterate with integer datatypes. An sample is to be found on a page for do loop statements.
The negotiation for retriving examples leads to choose either a character or a number. And until a boolean statement is not recognized redirect text like above
Loop Until n = ""
is the easy part.
A newline for an integer value is not necessary a boolean value. The integer can be a boolean value. If integers are dissected until they can be used for a boolean logic the possibiltiy can be used for iterations.
So a string like Text "Label1" is not an obvious boolean value.
I can not sample the question with an answer that takes the whole process apart, but post a part that exits the loop linking the string to a boolean value.
Public Class Form1
Private myValue As Object
ReadOnly AntiPanel As New Label
Private boolenValueTools As Boolean
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim message, title, defaultValue As String
' Set prompt.
message = " Enter a word. If you would like to quit, type: EXIT in the inputbox"
' Set title.
title = "InputBox Demo"
defaultValue = "1" ' Set default value.
'' Display dialog box at position 100, 100.
'myValue = InputBox(message, title, defaultValue, 100, 100)
'' If user has clicked Cancel, set myValue to defaultValue
'If myValue Is "" Then myValue = defaultValue
' Display message, title, and default value.
Do
myValue = InputBox(message, title, defaultValue)
If myValue = "EXIT" Then boolenValueTools = True
Loop Until boolenValueTools = True
' If user has clicked Cancel, set myValue to defaultValue
If myValue Is "" Then myValue = defaultValue
Me.Controls.Add(AntiPanel)
With AntiPanel
.AutoSize = True
.BackColor = Color.Transparent
.Location = New Point(100, 100)
.Font = New Font("Consolas", 55.75, FontStyle.Regular)
.Text = myValue 'in my case also known as NotNamedInputBoxTextString
End With
End Sub
End Class

Problems with "running" functionality

I am a new programmer learning Visual Basic.
Right now, I'm working on a project about a softball scoreboard. I have been working on this project for a bit, and I am confused on 1 thing.
The thing I am confused on is that I put in a messagebox that said invalid input for negative numbers, but it does not delete it from lstScores and even though the message box appears it still counts as a inning input.
If runs < 0 Then
MessageBox.Show(VALID_MESSAGE)
This is the code:
Public Class frmSoftballScoreboard
Const VALID_MESSAGE As String = "Enter valid runs value"
Const ONLY_MESSAGE As String = "Only seven innings are allowed"
'Declaring array
Dim scores(6) As Double
'declaring variables
Dim runs As String
Dim runningScore As Integer = 0
Dim i As Integer = 0
Dim out As Double
'page load event
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
lstScores.Items.Add("Runs : Running Score")
End Sub
'Enter score button
Private Sub btnScore_Click(sender As Object, e As EventArgs) Handles btnScore.Click
If i < scores.Length Then
'display inputbox to the user
runs = InputBox("Enter score for " & (i + 1) & " innings", "Score")
'if runs is entered
If runs <> "" Then
'parse the value of runs
If (Double.TryParse(runs, out)) Then
'parse the runs and add it to the array scores()
scores(i) = Double.Parse(runs)
runningScore += scores(i)
'add the rainfall value to the listbox along with month name
lstScores.Items.Add(scores(i) & " :" & runningScore)
'increment the value of i
i = i + 1
Else
'display error message
MessageBox.Show(VALID_MESSAGE)
lblTotal.Text = ""
End If
Else
'if runs is empty then display error message
MessageBox.Show("Enter runs for " & i & "innings")
End If
Else
MessageBox.Show(ONLY_MESSAGE)
End If
If runs < 0 Then
MessageBox.Show(VALID_MESSAGE)
End If
'calculate total runs And display on the lable
If scores(6) = 7 Then
lblTotal.Text = String.Format("final score is {0}", scores.Sum())
End If
End Sub
'Clear Menu click
Private Sub ClearToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles mnuClear.Click
lstScores.Items.Clear()
lblTotal.Text = ""
'reset i to 0
i = 0
End Sub
'Exit Menu click
Private Sub ExitToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles mnuExit.Click
'close application
Application.Exit()
End Sub
End Class
I would really appreciate it if you could help. Thank you.
Private Sub btnScore_Click(sender As Object, e As EventArgs) Handles btnScore.Click
If i < scores.Length Then
'display inputbox to the user
runs = InputBox("Enter score for " & (i + 1) & " innings", "Score")
'if runs is entered
If runs < 0 Then
MessageBox.Show(VALID_MESSAGE)
Exit Sub
ElseIf runs <> "" Then
'parse the value of runs
If (Double.TryParse(runs, out)) Then
'parse the runs and add it to the array scores()
scores(i) = Double.Parse(runs)
runningScore += scores(i)
'add the rainfall value to the listbox along with month name
lstScores.Items.Add(scores(i) & " :" & runningScore)
'increment the value of i
i = i + 1
Else
'display error message
MessageBox.Show(VALID_MESSAGE)
lblTotal.Text = ""
End If
Else
'if runs is empty then display error message
MessageBox.Show("Enter runs for " & i & "innings")
End If
Else
MessageBox.Show(ONLY_MESSAGE)
End If
If runs < 0 Then
MessageBox.Show(VALID_MESSAGE)
End If
'calculate total runs And display on the lable
If scores(6) = 7 Then
lblTotal.Text = String.Format("final score is {0}", scores.Sum())
End If
End Sub
This is the reason why if you input invalid data it will add into lstScores, because your If statement.. is in bottom of your code, although is not recommend where you put the If else statement... Remember reading of the code is start in top to bottom.
Your first If statement is like this. If runs <> "" then ...., of course if you type the -1 value in the Input Text the Boolean will result to true, If -1 <> "" = true, then it will proceed to the statement which is
If (Double.TryParse(runs, out)) Then
'parse the runs and add it to the array scores()
scores(i) = Double.Parse(runs)
runningScore += scores(i)
'add the rainfall value to the listbox along with month name
lstScores.Items.Add(scores(i) & " :" & runningScore)
'increment the value of i
i = i + 1
This is the line of code even the value is invalid or not it still adding value in the lstScores, lstScores.Items.Add(scores(i) & " :" & runningScore)
Now after that statement you will receive a message which is :
Enter valid runs value
If runs < 0 Then
MessageBox.Show(VALID_MESSAGE)
End If
That code is the reason why you receiving the message. If you input -1 of course the result of boolean is true, why? -1 is lessthan to 0 which is true.
The thing i do is, I've insert If statement.. above, which is If runs < 0 then .... and also Exit Sub to instantly end the statement. If you input -1 to Input Text the result is something like this, if runs(-1) lessthan to 0 the Boolean result is true then it will proceed to statement which is the Message and Exit Sub.
Try my code above, and also use Breakpoints.. Hope this helps..

Code iterating through whole string in hangman

How can I stop my code from iterating through a whole string stating whether the input from the user matches that of the random string bearing in mind this is for a hangman game, I want the code to just display once if the user's chosen letter is either correct or incorrect rather than displaying up too eight times.
Sub letterInput()
For i As Integer = 0 To randomWord.Length - 1
If userInput = randomWord(i) Then
MessageBox.Show("correct")
ElseIf userInput <> randomWord(i) Then
MessageBox.Show("incorrect")
Label4.Text = counter
Exit for
End If
Next
End Sub
Sub wordGeneration()
Dim wordUsed As Array = {"pizza", "noodle", "zombie", "object", "rowin", "running", "elephant", "lion"}
Dim random As New Random
randomWord = wordUsed(random.Next(0, 9))
Label2.Text = randomWord
End Sub
What I meant in the comments was that you just need to replace your for loop with a simple if/else. String.Contains checks the whole string already, so there is no need to iterate through each letter anymore:
Sub letterInput()
If randomWord.Contains(userInput) Then
MessageBox.Show("correct")
Else
MessageBox.Show("incorrect")
Label4.Text = counter
End If
End Sub

How to stop message box repeating because of array?

I'm trying to make a hangman game and to input "incorrect" if the user picks the wrong letter but it will keep repeating because of the randomWord which chooses the word from an array how do I stop this?
Sub wordGeneration()
Dim wordUsed As Array = {"pizza", "noodle", "zombie", "object", "rowin", "running", "elephant", "lion"}
Dim random As New Random
randomWord = wordUsed(random.Next(0, 8))
Label2.Text = randomWord
End Sub
Sub letterInput()
For i As Integer = 0 To randomWord.Length - 1
If userInput = randomWord(i) Then
MessageBox.Show("correct")
ElseIf userInput <> randomWord(i) Then
MessageBox.Show("incorrect")
Label4.Text = counter
End If
Next
End Sub
Simpler and faster to let VB do the search for you.
Sub letterInput()
if InStr(randomWord.Length, userInput) > 0
MessageBox.Show("correct")
Else
MessageBox.Show("incorrect")
Label4.Text = counter
End If
End Sub
Note: I am assuming userInput is a single character.