How to display an array - vb.net-2010

I have to make a Snakes and Ladders game in VB, and I needed some help on making the game board. I wanted to use a 2-D array to make the 100 square game board, and I'm having trouble displaying the game board. This is what I have so far:
Private Sub btnLetsGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLetsGo.Click
frmGameBoard.Show()
Me.Hide()
Call gameBoard()
End Sub
Sub gameBoard()
Dim SnakesAndLaddersGameBoard(9, 9) As String
SnakesAndLaddersGameBoard(0, 0) = "1"
SnakesAndLaddersGameBoard(0, 1) = "2"
SnakesAndLaddersGameBoard(0, 2) = "3"
SnakesAndLaddersGameBoard(0, 3) = "4"
SnakesAndLaddersGameBoard(0, 4) = "5"
SnakesAndLaddersGameBoard(0, 5) = "6"
SnakesAndLaddersGameBoard(0, 6) = "7"
SnakesAndLaddersGameBoard(0, 7) = "8"
SnakesAndLaddersGameBoard(0, 8) = "9"
SnakesAndLaddersGameBoard(0, 9) = "10"
End Sub
How can I make this much show on the form? After that, I'll make the rest of the game board, but I can't even get this much to work.
I'd appreciate any help, thank you.

There are two approaches to achieve this-
First--
Put a FlowLayoutPanel on form.
Add 100 labels to it (dynamically) with numbering 100 to 1
Second--
Use graphics to write text on the form (In the 'OnPaint' method, use 'e.DrawString')
Mark as answer if helpful.
Revert if any query.

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 can I implement the use of two textboxes for my calculator?

The purpose of my assignment is to create a calculator that uses number inputs from two textboxes. The calculator works when only dealing with a single textbox(boxequation1) but I need it to accept another input from the other textbox(boxequation2). Is there any way to input a number into boxequation1, select an operation, input a number into boxquation2, and then compute the result?
Public Class Form1
Private Sub ButtonClickMethod(sender As Object, e As EventArgs) Handles num0.Click, num1.Click, num2.Click, num3.Click, num4.Click, num5.Click, num6.Click, num7.Click, num8.Click, num9.Click, opdivision.Click, opmultiply.Click, opdecimal.Click, opclear.Click, opminus.Click, opadd.Click, opequal.Click
Dim button As Button = CType(sender, Button)
If button.Name = "num1" Then
boxequation1.Text = boxequation1.Text + "1"
End If
If button.Name = "num2" Then
boxequation1.Text = boxequation1.Text + "2"
End If
If button.Name = "num3" Then
boxequation1.Text = boxequation1.Text + "3"
End If
If button.Name = "num4" Then
boxequation1.Text = boxequation1.Text + "4"
End If
If button.Name = "num5" Then
boxequation1.Text = boxequation1.Text + "5"
End If
If button.Name = "num6" Then
boxequation1.Text = boxequation1.Text + "6"
End If
If button.Name = "num7" Then
boxequation1.Text = boxequation1.Text + "7"
End If
If button.Name = "num8" Then
boxequation1.Text = boxequation1.Text + "8"
End If
If button.Name = "num9" Then
boxequation1.Text = boxequation1.Text + "9"
End If
If button.Name = "num0" Then
boxequation1.Text = boxequation1.Text + "0"
End If
If button.Name = "opdecimal" Then
boxequation1.Text = boxequation1.Text + "."
End If
If button.Name = "opequal" Then
Dim equation1 As String = boxequation1.Text
Dim equation2 As String = boxequation2.Text
Dim result = New DataTable().Compute(equation1, Nothing)
boxresult.Text = result
End If
If button.Name = "opminus" Then
boxequation1.Text = boxequation1.Text + "-"
boxoperator.Text = boxoperator.Text + "-"
End If
If button.Name = "opmultiply" Then
boxequation1.Text = boxequation1.Text + "*"
boxoperator.Text = boxoperator.Text + "x"
End If
If button.Name = "opdivision" Then
boxequation1.Text = boxequation1.Text + "/"
boxoperator.Text = boxoperator.Text + "÷"
End If
If button.Name = "opadd" Then
boxequation1.Text = boxequation1.Text + "+"
boxoperator.Text = boxoperator.Text + "+"
End If
If button.Name = "opclear" Then
boxequation1.Clear()
boxoperator.Clear()
boxresult.Clear()
End If
End Sub
Private Sub opbackspace_Click(sender As Object, e As EventArgs) Handles opbackspace.Click
boxequation1.Text = boxequation1.Text.Remove(boxequation1.Text.Count - 1)
End Sub
End Class
I'm having a lot of fun with your homework.
Now... I'm not sure how I should do to help you. I initially wanted to code it and obfuscate parts of the code so you could check at what's clear and understand the rest by yourself, but on the other hand I have no idea if that would really help. I though that maybe you would do better with more explanations.
So I re-coded the whole thing, loosely based on what you posted earlier.
I heavily commented my work so you will be able to understand why I did things that war, but really you can and should ask me questions about everything which isn't cristal clear in this.
And, once you feel more confident about it, you should scrap my work and code it again, but from scratch this time. You're doing this to learn, after all!
Here what it looks like:
.-.-.-.-.-.-.-.-.
Here's a very cusomized New() Sub. It's not how I coded it; I needed only the 3 first lines of this monstruosity, but I wanted you to see the rest of it because that's how I set up my controls in the designer.
You should set up your controls names, texts and tags in the designer, really. This part really is here only because it was easier to show you these settings this way.
Private Sub New()
InitializeComponent()
_currentTextBox = Number1TextBox
_locked = False
ResultsTextBox.TextAlign = HorizontalAlignment.Center
ResultsTextBox.Text = "SUPER DUPER CALCULATOR"
For Each textBox As System.Windows.Forms.TextBox In {ResultsTextBox, Number1TextBox, Number2TextBox}
'This prevent the user from writing in your textboxes instead of using the buttons.
textBox.ReadOnly = True
Next
'I used the .Text and .Tag properties to make the code easier to manage. Observe:
num0Button.Text = "0"
num1Button.Text = "1"
num2Button.Text = "2"
num3Button.Text = "3"
'...
num9Button.Text = "9"
opAddButton.Text = "+"
opMinusButton.Text = "-"
opMultiplyButton.Text = "x"
opDivideButton.Text = "÷"
For Each button As Button In {num1Button, num2Button, num3Button, num4Button, num5Button, num6Button, num7Button, num8Button, num9Button}
button.Tag = "number"
Next
For Each button As Button In {opAddButton, opMinusButton, opMultiplyButton, opDivideButton}
button.Tag = "operation"
Next
num0Button.Tag = "numberZero"
opDecimalButton.Tag = "decimal"
opBackspaceButton.Tag = "backspace"
opEqualButton.Tag = "equal"
End Sub
And now for the real code: the subs that your class will need and use:
'Class variables are useful to remember informations which will be useful at several unrelated places.
'_currentTextBox is a pointer to the TextBox which is currently being filled
Private _currentTextBox As System.Windows.Forms.TextBox = Number1TextBox
'_Llocked will prevent the user from messing with the calculator after he pressed "equal"
Private _locked As Boolean = False
'I didn't like this idea but I went with it since it was your initial method.
'Notice how shoter this iteration of your idea is. Strive to shorten your code while making your variable names much easier to read.
'For real, make sure your variables are aptly names. Every control should be identified as such (the button num0 should be names num0Button for example)
'Code is hard enough to read without making it sibylline
Private Sub ButtonClickMethod(sender As Object, e As EventArgs) Handles num0Button.Click, num1Button.Click, num2Button.Click, num3Button.Click, num4Button.Click, num5Button.Click, num6Button.Click, num7Button.Click, num8Button.Click, num9Button.Click, opDivideButton.Click, opMultiplyButton.Click, opDecimalButton.Click, opClearButton.Click, opMinusButton.Click, opAddButton.Click, opEqualButton.Click, opBackspaceButton.Click
'DirectCast is more strick than CType. For this operation, it doesn't really make a difference, but that's the one you want anyway.
Dim button As System.Windows.Forms.Button = DirectCast(sender, System.Windows.Forms.Button)
'The boolean _locked prevent the user from messing with your beautiful calculator.
If Not _locked Then
'This is where the .Tag property save lifes. All numbers (but zero) are "number" now. BAM!
Select Case button.Tag.ToString
Case "number"
_currentTextBox.Text += button.Text
Case "numberZero"
'You don't want your clever teacher to try to divide by zero, or create a number with 5 zeros before the actual number.
'This is how you can do this.
If _currentTextBox.Text.Length > 0 Then
_currentTextBox.Text += button.Text
End If
Case "decimal"
If _currentTextBox.Text.Length > 0 AndAlso Not _currentTextBox.Text.Contains(".") Then
_currentTextBox.Text += button.Text
End If
Case "operation"
ResetOperationTextBoxes()
'here's a nifty visual cue about which operation has been selected. It's not really important.
button.BackColor = Color.LightSalmon
'This label will be used to Calculate() the operation. It's important!
OpLabel.Text = button.Text
Case "backspace"
If _currentTextBox.Text.Length > 0 Then
_currentTextBox.Text = _currentTextBox.Text.Substring(0, _currentTextBox.Text.Length - 1)
End If
Case "equal"
'I could have put the code here instead of making another sub, but I didn't.
'There are two valid reasons for this.
'1- This code might be useful on it's own later: maybe something else will Calculate() or LockCalculator or ResetCalculator later.
'2- try to avoid blobs of code. A big and complex sub is easier to understand when it's divided between several clean and clear smaller subs.
' (of course, you cannot always subdivise Subs. Use common sense)
Calculate()
End Select
End If
'This check is all alone because I want it to work even if the calculator is locked.
If button.Tag.ToString = "clear" Then
ResetCalculator()
End If
End Sub
Private Sub Calculate()
'Always make checks to make sure that things are going the way you think they should be going.
'for example, here I want to have 2 numbers and an operation, er else I'll just ignore this click.
If Number1TextBox.Text.Length > 0 AndAlso Number2TextBox.Text.Length > 0 And OpLabel.Text <> "?" Then
'If the user could mess with the textboxes, i would have to make further checks to avoid crashes, but I already force the user to use only numbers se we're cool.
Dim number1 As Double = Convert.ToDouble(Number1TextBox.Text)
Dim number2 As Double = Convert.ToDouble(Number2TextBox.Text)
Dim result As Double
Select Case OpLabel.Text
Case "+"
result = number1 + number2
Case "-"
result = number1 - number2
Case "x"
result = number1 * number2
Case "÷"
result = number1 / number2
End Select
ResultsTextBox.TextAlign = HorizontalAlignment.Right
ResultsTextBox.Text = result.ToString
LockCalculator(True)
End If
End Sub
'By using a boolean to signify to this Sub if I want to lock or unlock things, I make it easier to automatize this operation (and I have only one Sub instead of two).
Private Sub LockCalculator(ByVal isLocked As Boolean)
_locked = isLocked
'I'm kinda cheating here: I put the calculator inside a GroupBox just so I could be lazier and do this.
'Being lazy is great for a coder, as long as you think ahead (and avoid being a nuisance to yourself when you'll come back to this code and weep).
For Each control As System.Windows.Forms.Control In CalculatorGroupBox.Controls
control.Enabled = Not isLocked
Next
'Except that I want this button to always be available, so I enable it. This operation wouldn't be necessary if isLocked is True, but checking for that is longer than just doing it.
opClearButton.Enabled = True
End Sub
Private Sub ResetCalculator()
ResetNumberTextBoxes()
ResetOperationTextBoxes()
LockCalculator(False)
_currentTextBox = Number1TextBox
End Sub
Private Sub ResetNumberTextBoxes()
For Each textBox As System.Windows.Forms.TextBox In {Number1TextBox, Number2TextBox}
textBox.Text = ""
Next
'Mea Culpa: I shouldn't had done a For Each for 2 elements like that. I did it anyway. Please don't call the Fun Police on me.
'Also, you can now guess that using For Each loops to set up controls is a work method I like. Some don't like that.
'There is about as many ways to code something as there are coders. You have to find your own, sure, but then you'll get hired somewhere
'and they will absolutely hate everything that you do that isn't done the way they like it. And they will be right. On a big project where
'several coders works, at the same time and for month and years, you have to find a common ground or else the code will become a nightmare
'to understand and maintain. Trust me: being able to adapt quickly to other's work methodology is a GREAT skill in this field of work.
ResultsTextBox.TextAlign = HorizontalAlignment.Center
ResultsTextBox.Text = "SUPER DUPER CALCULATOR"
End Sub
Private Sub ResetOperationTextBoxes()
For Each button As System.Windows.Forms.Button In {opAddButton, opMinusButton, opMultiplyButton, opDivideButton}
button.BackColor = DefaultBackColor
Next
OpLabel.Text = "?"
End Sub
'This sub is great. It uses the _currentTextBox as a pointer. Maybe you're not familiar with pointers, I don't know. The short explanation is this:
'A pointer is like a phone number. You can give your number to several people without "losing" it. And if they call you and tell you something, they
'are all speaking to the same person.
'_currentTextBox is a pointer which can point toward Number1TextBox or Number2TextBox.
'This Event makes it so when the user click on Number1TextBox or Number2TextBox, the pointer updates it's "phone number" to the right box,
'so later when we'll write we'll write in the last one which was clicked on.
Private Sub NumberTextBoxes_Click(sender As Object, e As EventArgs) Handles Number1TextBox.Click, Number2TextBox.Click
_currentTextBox = DirectCast(sender, System.Windows.Forms.TextBox)
End Sub
Here you go. I hope that you'll have as much fun with coding as I did!
Before I go to sleep now, here's a few things that I think that you should make an effort to improve on:
1 Name your controls with really, really obvious names. Nobody care that the names are long, we all use the intelliSense anyway. But anything that we cannot guess at a glance is not clear enough!
2 Same thing with your variables. Same for everything which has a name, in fact. If you show your work to a teammate and he's not able to guess which control you're speaking about just by it's name, it's not clear enough!
3 The rest you will learn as you persevere through understanding your friend, the computer.
4 You should turn on Explicit and Strict mode. It'll help you understand the type you're working with and how they interact. It'll reduce dramatically the risk of awful manipulations. In fact, as though the more experience a coder has, the less he'll need these options, the more experienced a coder is, the more likely he'll be to have those two little lines of code at the beginning of all his works...
Here's how I begin every page of VB code at home:
.-.-.-.-.-.-.-.-.
4 Ask questions! To me, to classmates, to teachers! Ask questions to everything that moves!
Good luck!

Automatic decimal places in textbox

It looks very strange, but I can't find an online solution for my problem! At least in VB.NET.
Here's the deal:
I have a TextBox in a form (limited to numbers by a KeyPress event) and want to keep two decimal places as long as the user inputs his data.
For example, if the TextBox is blank, then, when the user presses, let's say, "2", the TextBox shows "0,02". Then, if the user presses "7", the TextBox shows "0,27". Then again, by pressing "6", it shows "2,76" and so on...
I managed to do this for one decimal place with the code:
Select Case Me.TextBox.Text
Case ""
Case ","
Me.TextBox.Text = ""
Case Else
Me.TextBox.Text = Strings.Left(Replace(Me.TextBox.Text, ",", ""), Strings.Len(Replace(Me.TextBox.Text, ",", "")) - 1) & "," & Strings.Right(Replace(Me.TextBox.Text, ",", ""), 1)
Me.TextBox.SelectionStart = Len(Me.TextBox.Text)
End Select
Please note that: 1. This code's running on a TextChanged event; 2. I'm from Portugal and here we use a comma (",") instead of a dot (".") for the decimal separator.
Could you help me to adjust my piece of code to work properly with two decimal places?
Any help will be very appreciated. And, as always, thank you all in advance.
Here's a custom class I've made which does what you require:
Public Class FactorDecimal
Private _value As String = "0"
Public DecimalPlaces As Integer
Public Sub AppendNumber(ByVal Character As Char)
If Char.IsNumber(Character) = False Then Throw New ArgumentException("Input must be a valid numerical character!", "Character")
_value = (_value & Character).TrimStart("0"c)
End Sub
Public Sub RemoveRange(ByVal Index As Integer, ByVal Length As Integer)
If _value.Length >= Me.DecimalPlaces + 1 AndAlso _
Index + Length > _value.Length - Me.DecimalPlaces Then Length -= 1 'Exclude decimal point.
If Index + Length >= _value.Length Then Length = _value.Length - Index 'Out of range checking.
_value = _value.Remove(Index, Length)
If _value.Length = 0 Then _value = "0"
End Sub
Public Overrides Function ToString() As String
Dim Result As Decimal
If Decimal.TryParse(_value, Result) = True Then
'Divide Result by (10 ^ DecimalPlaces) in order to get the amount of decimal places we want.
'For example: 2 decimal places => Result / (10 ^ 2) = Result / 100 = x,xx.
Return (Result / (10 ^ Me.DecimalPlaces)).ToString("0." & New String("0"c, Me.DecimalPlaces))
End If
Return "<parse error>"
End Function
Public Sub New(ByVal DecimalPlaces As Integer)
If DecimalPlaces <= 0 Then DecimalPlaces = 1
Me.DecimalPlaces = DecimalPlaces
End Sub
End Class
It works by letting you append numbers to form a long string of numerical characters (for example 3174 + 8 = 31748), then when you call ToString() it does the following:
It parses the long number string into a decimal (ex. "31748" => 31748.0)
It divides the decimal by 10 raised to the power of the amount of decimals you want (for example: 2 decimals => 31748.0 / 102 = 317.48).
Finally it calls ToString() on the decimal with the format 0.x - where x is a repeating amount of zeros depending on how many decimals you want (ex. 2 decimals => 0.00).
NOTE: This solution adapts to the current system's culture settings and will therefore automatically use the decimal point defined in that culture. For example in an American (en-US) system it will use the dot: 317.48, whereas in a Swedish (sv-SE) or Portuguese (pt-PT) system it will use the comma: 317,48.
You can use it like this:
Dim FactorDecimal1 As New FactorDecimal(2)
Private Sub TextBox1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox1.KeyPress
If Char.IsNumber(e.KeyChar) = False Then
e.Handled = True 'Input was not a number.
Return
End If
FactorDecimal1.AppendNumber(e.KeyChar)
TextBox1.Text = FactorDecimal1.ToString()
End Sub
Private Sub TextBox1_KeyDown(sender As Object, e As KeyEventArgs) Handles TextBox1.KeyDown
Dim TargetTextBox As TextBox = DirectCast(sender, TextBox)
e.SuppressKeyPress = True
Select Case e.KeyData 'In order to not block some standard keyboard shortcuts (ignoring paste since the pasted text won't get verified).
Case Keys.Control Or Keys.C
TargetTextBox.Copy()
Case Keys.Control Or Keys.X
TargetTextBox.Cut()
Case Keys.Control Or Keys.A
TargetTextBox.SelectAll()
Case Keys.Back, Keys.Delete 'Backspace or DEL.
FactorDecimal1.RemoveRange(TextBox1.SelectionStart, If(TextBox1.SelectionLength = 0, 1, TextBox1.SelectionLength))
TextBox1.Text = FactorDecimal1.ToString()
Case Else
e.SuppressKeyPress = False 'Allow all other key presses to be passed on to the KeyPress event.
End Select
End Sub
Online test: http://ideone.com/fMcKJr
Hope this helps!
Thank you #Visual Vincent. Your method works fine. However I managed to find a simpler way of doing what I asked by the following code:
Private Sub TextBox_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox.KeyPress
If Not Char.IsDigit(e.KeyChar) And Not Char.IsControl(e.KeyChar) Then
e.Handled = True
End If
End Sub
Private Sub TextBox_TextChanged(sender As Object, e As EventArgs) Handles TextBox.TextChanged
Select Case Val(Replace(Me.TextBox.Text, ",", "."))
Case 0 : Me.TextBox.Text = ""
Case Else
Me.TextBox.Text = Format(Val(Replace(Me.TextBox.Text, ",", "")) / 100, "0.00")
Me.TextBox.SelectionStart = Len(Me.TextBox.Text)
End Select
End Sub
This piece of code look suspicious simple to me. For now it works fine and does the trick exactly how I wanted. Maybe there's something missing to me, or maybe I wasn't clear enough on the description of my goal.
If you find any flaw on my method, please feel free to point it! I'll appreciate it very much.

Label movement not making sense?

I am playing around in vb.net and decided to make a 23x18 grid of labels, 234 labels in total. Each label is titled 'Label(x)' from 1 to 234. I have another label which, when I press a key (wasd), should move in the corresponding direction. In most cases it does this correctly, but in others it jumps over them, skipping one or maybe two labels altogether. I can't imagine why this is.
Dim lab As Label
Dim x As Integer
Private Sub Form1_KeyDown1(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
For x = 1 To 234
lab = Controls("Label" & x)
If e.KeyCode = Keys.A And lab.Location = New Point(lblPlayer.Location.X - 20, lblPlayer.Location.Y) And lab.Text <> "#" Then
lblPlayer.Location = lab.Location
ElseIf e.KeyCode = Keys.D And lab.Location = New Point(lblPlayer.Location.X + 20, lblPlayer.Location.Y) And lab.Text <> "#" Then
lblPlayer.Location = lab.Location
ElseIf e.KeyCode = Keys.W And lab.Location = New Point(lblPlayer.Location.X, lblPlayer.Location.Y - 13) And lab.Text <> "#" Then
lblPlayer.Location = lab.Location
ElseIf e.KeyCode = Keys.S And lab.Location = New Point(lblPlayer.Location.X, lblPlayer.Location.Y + 13) And lab.Text <> "#" Then
lblPlayer.Location = lab.Location
End If
Next x
End Sub
I have considered it could possibly be due to a wrong label location in the grid (which I have confirmed to be false) but even if that was so, the label shouldn't move at all, rather than jumping. The labels it jumps over are consistent, but I honestly cannot see why those specific labels are being skipped.
I have since added a sub which makes every label the 'player' has passed over change colour, and that has shown me that it doesn't even pass over the 'jumped' label, it skips them completely, as they remain the same colour. I honestly cannot see how this code allows for that, as it should only check for the label the in the correct position, and will only move if that label is found there.
Am I having a complete brain fart here? Sorry if this is the wrong place to ask questions as specific as this. Please direct me to the correct place if this is not the place for scenarios such as this.

Null Reference Exception was Unhandled

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. :-)