Visual Basic Random Number Guessing Game - vb.net

I need some help for an assignment in class. I'm trying to create a random number guessing game that must have a loop. Basically, you input a number as a guess and the program will display a message telling you whether the guess is too high, too low, or correct, and it will loop until you get the guess correct. The program also counts the number of guesses you've made.
Here is the form:
And here is the code I have so far:
Private Sub btnDisplay_Click(sender As Object, e As EventArgs) Handles btnDisplay.Click
Dim decNumber As Decimal
Dim rand As New Random
Dim decGuess As Decimal
Dim intCount As Integer = 0
decGuess = CDec(txtGuess.Text)
Do
decNumber = rand.Next(1, 100)
intCount += 1
lblCount.Text = intCount.ToString
If decNumber < decGuess Then
lblResponse.Text = "Too low, try again."
ElseIf decNumber > decGuess Then
lblResponse.Text = "Too high, try again."
ElseIf decNumber = decGuess Then
lblResponse.Text = "Correct."
End If
Loop Until decGuess = decNumber
End Sub
I'm not quite sure what the error in the code is but whenever I hit "Display" the guess count is a very high number and the message shown in the label is always just "Correct.", so my question is how do I fix this and write the loop correctly?
Update:
Public Class Form1
Dim intNumber As Integer
Dim rand As New Random
Dim intGuess As Integer
Dim intCount As Integer
Private Sub btnNew_Click_1(sender As Object, e As EventArgs)
lblResponse.Text = String.Empty
txtGuess.Clear()
lblCount.Text = String.Empty
intNumber = rand.Next(1, 100)
End Sub
Private Sub btnGuess_Click(sender As Object, e As EventArgs) Handles btnGuess.Click
intGuess = CInt(txtGuess.Text)
If intNumber < intGuess Then
lblResponse.Text = "Too high, try again."
ElseIf intNumber > intGuess Then
lblResponse.Text = "Too low, try again."
ElseIf intNumber = intGuess Then
lblResponse.Text = "Correct."
End If
intCount += 1
lblCount.Text = intCount.ToString
End Sub

There are quite a few errors with your code:
1. The definition of your random number
You are generating the random number every loop, meaning that rather than there being a fixed number that you are trying to guess, the number is changing.
Even if you are defining the random number outside the loop, the number changes every time that you click the button.
You will need to define it as global variable outside the subroutines and only change it when you press the reset button
2. The definition of intcount
intcount is set to 0 every time you click the button since it is defined within the button click subroutine, which I do not think is desired.
3. The fact that you are using a loop
You do not need the loop at all. Unless you want your programme to enter an infinite loop and crash every time you press your button and your guess is incorrect, you should remove the loop and just use the code inside it.
4. Wrong data types used
decnumber should be an integer, since random.next() returns an integer value (you might also rename it to ToGuess)
decGuess = CDec(textGuess.Text)
should be
decGuess = CInt(textGuess.Text)
since if you input a decimal, you will never be able to guess the number
The reason for the programme always outputting "correct" is because rather than you changing your guess so it is the same as the random number, the computer is 'guessing' your guess by changing the random number so that it will eventually become your guess, incrementing # of guesses every time.
UPDATE:
The reason that your new button is not working is because it does not handle its click. Assuming you have called your new button btnNew, try replacing:
Private Sub btnNew_Click_1(sender As Object, e As EventArgs)
with:
Private Sub btnNew_Click_1(sender As Object, e As EventArgs) Handles btnNew.Click
Next time when adding a subroutine for a buttons click, try double clicking the button in the design view in visual studio. This will automatically generate the click subroutine.
Another problem that you have is that you have not generated your random number when your form loads. To solve this, double click on your form in designer view to generate the load subroutine, and then programmatically press the button
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
btnNew.PerformClick()
End Sub
also, thanks to jimi's comment, remember to set intCount to 0 when pressing btnNew

Related

Infinite loop is causing the form to not show up vb

I have an infinite loop in this sub because I want the program to keep testing this process to see if the variable has changed. When I run the program in the debugger, nothing shows up, including the form however when I removed the infinite loop from the program, the form showed up again. Does anyone know why this is happening? I should also mention I've tried a DO LOOP as well. Can anyone help?
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim greenCount As Integer
Dim looptest As Boolean = True
While looptest = True
For Each control In Me.Controls.OfType(Of Button)
If control.BackColor = Color.Lime Then
greenCount += 1
End If
Next
txtFielder.Text = greenCount.ToString
End While
End Sub
You need to get rid of all that code regardless. Depending on how you're changing the BackColor of those Buttons in the first place, updating the lime count might be best done there. Otherwise, you should be handling the appropriate event, e.g.
Private limeButtonCount As Integer = 0
Private Sub Buttons_BackColorChanged(sender As Object, e As EventArgs) Handles Button3.BackColorChanged,
Button2.BackColorChanged,
Button1.BackColorChanged
If DirectCast(sender, Button).BackColor = Color.Lime Then
limeButtonCount += 1
Else
limeButtonCount -= 1
End If
TextBox1.Text = limeButtonCount.ToString()
End Sub
Note that this code assumes that there are only two possible BackColor values and that all Buttons are not lime by default. If your scenario is a bit more complex than that then you may need to change a code a little, e.g.
Private limeButtonCount As Integer = 0
Private Sub Buttons_BackColorChanged(sender As Object, e As EventArgs) Handles Button3.BackColorChanged,
Button2.BackColorChanged,
Button1.BackColorChanged
limeButtonCount = Controls.OfType(Of Button)().Count(Function(b) b.BackColor = Color.Lime)
TextBox1.Text = limeButtonCount.ToString()
End Sub
Form.Load occurs before a form is displayed for the first time.
This means that you'll never see your form as long as you loop in this event. You probably want to use the Shown event instead.

Calculate cost of several items with tax and a discount

Can anyone help with this school task I have
The task is to ask the user for items and the cost of the items until they chose to stop. Then combine all the costs and take 20% VAT and 10% off from 2 randomly selected items.
Here is the code I have so far (I have 2 buttons and a listbox)
Public Class Form1
Dim CurrentA As Integer
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim Items(CurrentA) As String
Dim Coins(CurrentA) As Single
Dim Stay As String
CurrentA = 0
Do Until CurrentA = 20
Items(CurrentA) = InputBox("Please Enter The Item")
Coins(CurrentA) = InputBox("Please Enter The Cost Of The Item")
Stay = InputBox("Type Yes If More Items or Type No if no More")
Stay = Stay.ToLower
If Stay = "yes" Then
End If
If Stay = "no" Then
Exit Do
End If
ListBox1.Items.Add(Items(CurrentA) & " " & Coins(CurrentA))
CurrentA += 1
Loop
End Sub
End Class
First, a few comments on the code you presented.
Dim CurrentA As Integer
'An Integers default value is zero, I don't see why this is a class level variable
'always declare variables with as narrow a scope as possible
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim Items(CurrentA) As String 'Declares an Array of Type String with an Upper Bound of 0
'Upper Bound is the highest index in the array
'Arrays start with index 0
'So your array will have 1 element at index 0
Dim Coins(CurrentA) As Single
Dim Stay As String
CurrentA = 0 'unnecessary because the default of CurrentA is already 0, but OK for clarity because it could have been changed elsewhere
'This is behaving like a console application with the code repeating in a loop.
'In Windows Forms it would be more likely to do this in a button click event (btnAddItem)
Do Until CurrentA = 20
'On the first iteration CurrentA = 0
'On the second iteration CurrentA = 1 - this exceeds the size of your array
'and will cause an index out of range error
Items(CurrentA) = InputBox("Please Enter The Item")
'With Option Strict on you must change the input to a Single
Coins(CurrentA) = CSng(InputBox("Please Enter The Cost Of The Item"))
Stay = InputBox("Type Yes If More Items or Type No if no More")
Stay = Stay.ToLower 'Good! The user might no follow directions exactly
If Stay = "yes" Then
'This is kind of silly because it does nothing
End If
'Lets say I say no on the first iteration
'This avoids the index out of range error but
'nothing is added to the list because you Exit the loop
'before adding the item to the ListBox
If Stay = "no" Then
Exit Do
End If
ListBox2.Items.Add(Items(CurrentA) & " " & Coins(CurrentA))
CurrentA += 1
Loop
End Sub
We could use arrays but not knowing how many items will be added means either making the array bigger than needed or using Redim Preserve on every addition. A much better choice is a List(Of T). They work a bit like arrays but we can just add items without the ReDim stuff.
Private lstCost As New List(Of Single)
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
'Pretend this button is called btnAdd, and you have 2 test boxes
lstCost.Add(CSng(TextBox2.Text))
'The $ introduces an interpolated string. It is a step up form String.Format
ListBox2.Items.Add($"{TextBox1.Text} - {CSng(TextBox2.Text):C}") 'The C stands for currency
TextBox1.Clear()
TextBox2.Clear()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
'Pretend this button is called btnTotal
'Dim total As Single = (From cost In lstCost
' Select cost).Sum
Dim total As Single = lstCost.Sum
Label1.Text = total.ToString("C") 'C for Currency
End Sub

Ticket printing

I'm busy to write ticket program in Vb , everything is working perfectly
but when i'm printing things goes wrong,
the ticket is printing correctly ( in this example 3 ) the ticketnumbers are overlapping
example : 3 tickets 15200 , 15201 , 15203
3 tickets are printed but the 1520 is printed correct but on evey ticket the 1,2 a 3 are printed over each other
What the hell is going wrong ??
this is a part of the code
Private Sub PrintDocument1_PrintPage(sender As System.Object, e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
Dim AZ As String
Dim x As Integer
Dim LB1, LB2 As Integer
AZ = TextBox12.Text
For x = 0 To AZ - 1
LB1 = Val(TextBox1.Text) + x
e.Graphics.DrawString(LB1, New Font("Microsoft Sans Serif", 10), Brushes.Black, New Point(155, 265))
next
end sub
Sorry, I misread and gave you the wrong answer.
One way I've done this in the past was to call the printdocument.print inside a loop. The only problem with this is that you get a messagebox telling you that each page is printing so that may not be ideal.
Anyway, here is a method that you might be able to work off with. It's been a while since I've used the printdocument as I find the ReportViewer/Report is easier to work with.
'Widen the scope of LB1 so it can be used in both methods
Dim LB1, LB2 As Integer 'Declared outside of any methods (Class Level)
Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
e.Graphics.DrawString(LB1.ToString, New Font("microsoft sans serif", 10), Brushes.Black, New Point(155, 265))
End Sub
Private Sub btnPrint_Click(sender As Object, e As EventArgs) Handles btnPrint.Click
Dim AZ As Integer = CInt(NumericUpDown1.Value)
For x = 0 To AZ - 1
'We can get rid of this if we use a NumericUpDown control and set it
'to ensure we are working with a number.
If Not Integer.TryParse(TextBox1.Text, LB1) Then
'notify the user with maybe a messagebox that the input is invalid
Exit Sub
End If
LB1 += x
PrintDocument1.Print()
Next
End Sub
Again, I've not worked with this for a while but I seem to remember e.HasMorePages being a way of telling the PrintDocument to move to the next page. You might google up on it and see if it's a better alternative than looping and displaying the Print messagebox for each page like this code is doing. Hopefully it's at least gives you something to work off of.
EDIT --- THIS IS THE PROPER WAY OF DOING WHAT YOU'RE WANTING TO DO ---
I decided to go ahead and look into the HasMorePages myself and It would be the better and more proper solution. You would need to change a few things but here is an example of your code using it.
Dim LB1, LB2 As Integer 'Declared outside of any methods
Dim currentTicket = 0
Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
'how many tickets to print
Dim TotalTickets As Integer = CInt(NumericUpDown1.Value)
'build the current ticket number (I would look at my previous code
'which uses TryParse instead of Val as an invalid input could cause
'your application to fail)
LB1 = Val(TextBox1.Text) + currentTicket
'Print the ticket number on the page
e.Graphics.DrawString(LB1.ToString, New Font("microsoft sans serif", 10), Brushes.Black, New Point(155, 265))
'increase the currentTicket counter
currentTicket += 1
'did we go over the total number of tickets we want to print
If currentTicket < TotalTickets Then
'if not, we need to tell the printdocument that we have more to print
e.HasMorePages = True
End If
'otherwise, we'll stop there and print the pages we produced.
End Sub
This will give you the single dialog that shows how many pages are being printed instead of a single dialog per page.

Alternative Process

I have 2 buttons and a DataGridView with 2 Columns (0 & 1).
The 1st button transfers a randomized cell from the Column(1) to a TextBox. Then, it stores that Cell in variable (a), plus the cell that opposites it in variable (b).
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim rnd As New Random
Dim x As Integer = rnd.Next(0, Form1.DataGridView1.Rows.Count)
Dim y As Integer = 1
Dim a As String = Form1.DataGridView1.Rows(x).Cells(y).Value
Dim b As String = Form1.DataGridView1.Rows(x).Cells(y - 1).Value
TextBox3.Text = a
End Sub
The 2nd button, however, is supposed to compare if another TextBox's text has the same string variable (b) has as Strings. Now, if so, then it has to display a certain message and so on...
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If TextBox4.Text = b Then '<<< ISSUE HERE!
MsgBox("Correct! ^_^")
ElseIf TextBox4.Text = "" Then
MsgBox("You have to enter something first! O_o")
Else
MsgBox("Wrong! >,<")
End If
End Sub
The problem is that the variable (b) is surely not shared across the two "private" subs. And so, there is NOTHING to compare to in the 2nd button's sub! I presume that the solution here is to split the "randomization process" into a separate function, then execute it directly when the 1st button gets activated. Furthermore, that function's variables have to be SHARED somehow, and I certainly don't know how!
Thanks for Mr. Olivier, the code has been improved significantly! Yet, I still encounter a "wrong" comparison issue, somehow!
Dim RND As New Random
Dim x As Integer
Private Function GetCell(ByVal rowIndex As Integer, ByVal cellIndex As Integer) As String
Return Form1.DataGridView1.Rows(rowIndex).Cells(cellIndex).Value
End Function
Private Sub btnRoll_Click(sender As Object, e As EventArgs) Handles btnRoll.Click
x = RND.Next(0, Form1.DataGridView1.Rows.Count)
tbxRoll.Text = GetCell(x, 1)
End Sub
Private Sub btnSubmit_Click(sender As Object, e As EventArgs) Handles btnSubmit.Click
If tbxSubmit.Text = GetCell(x, 0) Then
MsgBox("Correct! ^_^")
ElseIf tbxSubmit.Text = "" Then
MsgBox("You have to enter something first! O_o")
Else
MsgBox("Wrong! >,<")
End If
End Sub</code>
Well, unbelievably, I read a guide about "comparison operations" in VB.net and tried out the first yet the most primal method to compare equality - which was to use .Equals() command - and worked like a charm! Thank God, everything works just fine now. ^_^
If tbxSubmit.Text.Equals(GetCell(x, 0)) Then
Alright now... This is going to sound weird! But, following Mr. Olivier's advise to investigate "debug" the code, I rapped the string I'm trying to compare with brackets and realized that it's been outputted after a break-line space! So, I used the following function to remove the "white-space" from both of the comparison strings! And it bloody worked! This time for sure, though. ^_^
Function RemoveWhitespace(fullString As String) As String
Return New String(fullString.Where(Function(x) Not Char.IsWhiteSpace(x)).ToArray())
End Function
If RemoveWhitespace(tbxSubmit.Text) = RemoveWhitespace(GetCell(x, 0)) Then
Turn the local variables into class fields.
Dim rnd As New Random
Dim x As Integer
Dim y As Integer
Dim a As String
Dim b As String
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
x = rnd.Next(0, Form1.DataGridView1.Rows.Count)
y = 1
a = Form1.DataGridView1.Rows(x).Cells(y).Value
b = Form1.DataGridView1.Rows(x).Cells(y - 1).Value
TextBox3.Text = a
End Sub
These fields can now be accessed from every Sub, Function and Property.
Of course Button3_Click must be called before Button2_Click because the fields are initialized in the first method. If this is not the case then you should consider another approach.
Create a function for the Cell access
Private Function GetCell(ByVal rowIndex As Integer, ByVal cellIndex As Integer) _
As String
Return Form1.DataGridView1.Rows(rowIndex).Cells(cellIndex).Value
End Function
And then compare
If TextBox4.Text = GetCell(x, y - 1) Then
...
And don't store the values in a and b anymore. If y is always 1 then use the numbers directly.
If TextBox4.Text = GetCell(x, 0) Then
...
One more thing: give speaking names to your buttons in the properties grid before creating the Click event handlers (like e.g. btnRandomize). Then you will get speaking names for those routines as well (e.g. btnRandomize_Click).
See:
- VB.NET Class Examples
- Visual Basic .NET/Classes: Fields

Getting upperbound and lowerbound from a textbox

I'm trying to figure out the code for a project but I don't completely understand it. The objective is to write a program that generates a set of 10 random numbers and stores it in an array (the 10 numbers display in the textbox correctly). It should have a button that will compute the minimum, maximum and average of the array. I cant seem to get the max and min values of it from a textbox. I know people don't post the answers and I'm not looking for that but if someone could tell my why what I'm doing for the max/min is wrong or point my in the right direction I would appreciate it. Thank you!
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim randomArray As New Random()
Dim randomNumber As Integer
For i = 1 To 10
randomNumber = randomArray.Next(1, 101)
displaynumbersTextBox1.AppendText(randomNumber & " ")
displaynumbersTextBox1.Text = Convert.ToString(randomNumber)
Next
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim randomArray As New Random()
Dim randomNumber As Integer
For i = 1 To 10
randomNumber = randomArray.Next(1, 101)
displaynumbersTextBox1.AppendText(randomNumber & " ")
Next
Dim min As Integer
min = displaynumbersTextBox1.Text.GetLowerBound()
displayminTextBox2.Text = min
End Sub
For starters, I see this code in Button1:
TextBox1.AppendText(randomNumber & " ")
TextBox1.Text = Convert.ToString(randomNumber)
The 2nd line negates the first. Just remove it. Instead, clear the textbox at the beginning of the button click handler.
Next, in button 2 the code goes through and re-creates a new set of random numbers, instead of using the set created from the first button. What is more, at no point are the numbers ever stored in an array. You need an array declared outside of either button, in in the code for Button1 set the elements of the array, so you can use those numbers again in Button2 more easily.