Jackpot
Up
Before attempting this project, please do the very easy 'Random Number' Project. 

In this 'Jackpot' project we will make a program resembling a slot machine - it will generate random numbers and if any of the numbers are sevens then there will be a 'prize' (a nice message!"). In this project you will learn about:

bulletvariable arrays
bulletFor...Next loops
bulletthe relationship between numbers and the conditions 'true' and 'false'
bulletrandom numbers (extra practice)

Make a new Windows Application project (File>New Project) with the name Jackpot. Click the Save All button or choose File>Save All and save the project into your VB folder with the name Jackpot. Don't forget to save your work every 10 minutes or so (you can use Ctrl-S for this).

We'll use the above picture as a background for our project so download it (right-click and choose Save Target As...) into your new Jackpot folder.

You might have got the impression from the Lander project that only PictureBox controls can contain pictures but in fact many other controls can contain pictures, including labels and the form itself. Click the BackgroundImage property of the form, choose Local Resource and Import, then import the picture you just saved. The picture's dimensions are 727 pixels by 500 pixels so set the form's Size property to 727,530 to match that. (The form needs to have an extra 30 pixels in height to accommodate the title bar.) Also set the form's text property to 'Jackpot by (YOUR NAME)'.

Add a label with the following properties: name = lblNum0, autosize = false, textalign = middlecenter, font.size = 100, text = 0, backcolor and font = your choice (I used Arial font with bold style).

Also make a label to completely cover the 'Spin' button in the picture, with properties: name = lblSpin, text = (empty), autosize = false. called lblSpin to the form and set properties until t. I chose Arial size 100 for the label. Choose your own colours. Your form should now look something like this (to save space this picture does not show the whole form):

We will actually be clicking this label as if it were a button, so why are we using a label instead of a button control? The answer is that a button cannot be made transparent but a label can - make the lblSpin label transparent now by setting its BackColor property to transparent (look in the Web colour palette).

Let's make the spin 'button' (really a label) put a random integer between 0 and 9 into the lblNum0 label. Having studied the 'Random Number' project, you will know what code to put in lblNum0:

lblNum0.Text = int(10 * Rnd())

Let's not forget that every program that uses the Rnd() function should have Randomize in the Form_Load procedure, so double-click the form and add the Randomize statement into the Form_Load procedure. Test your program - clicking the transparent label that covers the spin button should put random digits into the lblNum0 label.

Having got that working, let's think about how to put random digits into three labels at the same time. Copy the lblNum0 label and paste a copy of the label onto the form. Move the copy into the middle space on the picture and rename it lblNum1. Paste another copy and move it into the right space and rename it lblNum2.

NO

The following code, placed in the lblSpin procedure, should work fine for putting random numbers in each label:

lblNum0.Text = Int(10 * Rnd())
lblNum1.Text = Int(10 * Rnd())
lblNum2.Text = Int(10 * Rnd())

Try it!

Our program works OK, but doesn't behave much like a real slot machine. A real slot machine lets the number flash by for a random time before freezing each number, one by one. Let's try to simulate that. Add a timer control called tmr1 to the form by dragging a timer control from the Components group in the toolbox onto the form. The timer appears in a gray area under the form rather than on the form itself. Set the timer's interval property to 100 so that each text will change every 100 milliseconds or 10 times every second (100 milliseconds = 0.1 second). MOVE the three lines of code above into the timer control procedure, add the statement tmr1.enabled = true just above the three lines you have moved, then check that it makes the numbers change constantly:

Now we need to figure out how to 'freeze' numbers in the labels after a random time that is different for each label. Let's say we want the first label to be frozen after 1-2 seconds, the second after 2.5-3.5 seconds and the third after 4-5 seconds. We will create an 'array' called WaitTime to hold the three times (in seconds) that we want each of the three labels to 'spin' for. A normal variable can hold only a single variable, whereas an array can hold several. By adding the line

Dim WaitTime(3)

just under the Public Class declaration at the top of the code, we create an array called WaitTime that can hold three values. The first value will be held in WaitTime(0), the next in WaitTime(1), the last in WaitTime (2). (Often in computer programming, numbering starts at zero rather than one.)

The following code added to the lblSpin procedure can generate the desired random numbers and store them into the various parts of the array:

WaitTime(0) = 1 + Rnd()
WaitTime(1) = 2.5 + Rnd()
WaitTime(2) = 4 + Rnd()

Our label code also needs to record the time at which it was clicked. To do that we will use the DateAndTime.Timer property (not to be confused with the timer control that you added earlier). The DateAndTime.Timer property is the number of seconds that have elapsed since midnight. This is easier to work with than a normal time in hours, minutes and seconds, because the timer value is just a simple decimal number, the number of seconds since midnight. For example, at 2am the Timer property would be 7200 since 2am is 7200 seconds after midnight. So the complete code inside the lblSpin label procedure is now:

tmr1.Enabled = True
WaitTime(0) = 1 + Rnd()
WaitTime(1) = 2.5 + Rnd()
WaitTime(2) = 4 + Rnd()
StartTime = DateAndTime.Timer

Note that since we are introducing a new variable we need to declare that variable somewhere, but where? Recall that if a variable is used only in one procedure then it should be declared inside that procedure but if the variable is used in more than one procedure then it should be declared just after the class declaration, at the top of the code window, so that it can be accessed by multiple procedures. We will in fact be using this variable in two procedures so you should add the line

dim WaitTime(3)

just after the class declaration at the top of the code window. In fact you can declare the WaitTime array at the same time you declare the StartTime variable if you like, with a line like this:

dim WaitTime(3), StartTime

Now we need to modify the timer code so that the timer stops changing each text once its WaitTime time has been exceeded. The code below can do the job:

Dim SpinTime = DateAndTime.Timer - StartTime
Dim m As Integer
For m = 0 To 2
	If SpinTime < WaitTime(m) Then
		Num(m) = (Num(m) + 1) Mod 10
	End If
Next
lblNum0.Text = Num(0)
lblNum1.Text = Num(1)
lblNum2.Text = Num(2)

This code starts by calculating the SpinTime which is the number of seconds the labels have been 'spinning', found by subtracting the StartTime from the current time. But the really important part is the 5 lines shown in bold type above, which make up something called a loop...

Loops

Concentrate on the part of the code above which is in bold type. This is an example of a loop. Loops are a very important part of computer programs for they sometimes allow us to replace hundred of lines of code with just two or three. How does a loop work? The loop above begins by running the code inside the loop a first time, using the value of 0 for the counter variable 'm' (this variable is used only in this procedure, thus we have declared it inside the same procedure). The If structure begins by checking whether the SpinTime is less than the time that this label is allowed to spin, which we are calling its WaitTime.  If it is, then Num(0) is incremented (increased) by one. Num is an array of three variables that will be copied into the labels later into the code - it probably isn't possible to modify the labels from within the loop. The loop then repeats using m=1 and then m=2. Then the loop stops running and the code beneath the loop begins to run. In our example, you might be thinking that our loop has not made our code particularly neat or easier to understand... and you'd be right! The point is that you are learning about a technique that COULD make code much shorter - imagine if you had to set values for each member of an array with one thousand members instead of just three!

For...Next loops are very useful when code has to be run repeatedly for a known number of times (if we don't know how many times the loop should run then we use use something called a Do...Loop).

Did you notice that there was something unfamiliar in the line that adds one to the value stored in the Num variable? The tricky thing is that we want each labels to display only a digits 0-9 and never anything bigger than 9, so we have to make sure that when we add one to nine we actually return to zero instead of getting a ten. To do this we use a function called MOD (modulus) which returns the remainder when one number is divvied by another. For example 7 Mod 3 = 1, 18 Mod 5 = 3, 10 Mod 10 = 0 etc. The last part there, 10 Mod 10 = 0, shows how the Mod function will make the counting go from 9 to 0 instead of 10.

This code is being run 10 times every second, don't forget, so each label's text is being updated 10 times every second, provided its SpinTime is less than its WaitTime.

Your program should now be working fine now - we just have to add code to detect 'winning combinations'. Let's give rewards for anyone who gets one or more sevens when they spin the numbers.

Change the code inside the tmr1 procedure to the following:

Dim SpinTime = DateAndTime.Timer - StartTime
Dim m As Integer
For m = 0 To 2
	If SpinTime < WaitTime(m) Then
		Num(m) = (Num(m) + 1) Mod 10
	ElseIf m = 2 Then
		tmr1.Enabled = False
		checkwin()
	End If
Next
lblNum0.Text = Num(0)
lblNum1.Text = Num(1)
lblNum2.Text = Num(2)

We know already that the If statement checks whether the SpinTime is less than the WaitTime. If this is no longer true then instead of changing a Num value the ElseIf code is run. This checks whether the loop is processing the last label (m=2) and if it is then the timer control is disabled and the code calls a procedure called checkwin(). (When VB comes across  a word that it does not understand then it looks for a procedure with that name - the procedure will tell VB what to do next.) So we will make sure there IS such a procedure by adding this to the code (type the first line just above the End Class statement at the bottom of the code window and press Enter so that the other wrapper line is generated automatically).

Private Sub checkwin()
tmr1.Enabled = False
Dim sevenscount as integer
Dim n as integer
For n = 0 To 2
	sevenscount = sevenscount - (Num(n) = 7)
Next n
If sevenscount Then
	MsgBox ("You scored " & sevenscount & " seven(s). Well done!")
End If
End Sub

Remember: the 'checkwin' procedure is activated only when the timer code detects that the WaitTime of the last label (n=2) has been exceeded. The checkwin procedure include a line that disables the timer, so you should add a line anywhere in the lblSpin label code to enable it again:

tmr1.Enabled = True

The checkwin procedure includes these interesting lines:

For n = 0 To 2
    sevenscount = sevenscount - (Num(n)= 7)
Next n

When the sevenscount variable is created by the Dim statement it is given the value zero which in VB is equivalent to false. The For...Next loop examines each Num in turn and checks whether it is equal to 7. If this is true then the expression is equivalent to -1 since in VB true is always taken to be equivalent to -1. When the expression is false VB takes this to be equivalent to 0. Subtracting -1 from sevenscount is the same as adding 1 to sevenscount, so the sevenscount variable keeps track of the total number of sevens that have been found.

Now let's examine the code fragment below.

If sevenscount Then
	MsgBox ("You scored " & sevenscount & " seven(s). Well done!")
End If

You have learnt in a previous lesson that

If sevenscount Then

is the same as

If sevenscount = true Then

When forced to treat numbers as 'true' or 'false' conditions, VB treats all non-zero numbers as 'true' and zero as 'false', so the line following the If statement above is executed only if sevenscount is not zero.

Here is the complete code of the finished project in case you got lost:

For EXTRA CREDIT, can you...

bulletmodify the checkwin code so that the user can also win by getting two digits that are the same
bulletincrease the number of labels to four or five and change the code as appropriate. This should not be too difficult as we have been using a control array and a variable array
bulletadd new features that you have thought of yourself
bulletadd a sound to your project...

Click HERE to see how easy it is to add sound to this (or any other) program, then add a cash register sound to your Jackpot program. Click HERE to download a sound file called 'cashreg.wav' and make sure you save it into the same folder that holds your project files. If left-clicking does not give you a file-save dialog then try right-clicking.

Place the function declaration (from the Sound project) into the General Declarations area, just above or just below the DIM line. Change the checkwin code to:

Private Sub checkwin()
For n = 0 To 2
	sevenscount = sevenscount - (Num(n) = 7)
Next n
If sevenscount Then
	My.Computer.Audio.Play("cashreg.wav")
	'MsgBox ("You scored " & sevenscount & " seven(s). Well done!")
End If
End Sub

I've commented out the messagebox code so that the new sound is not drowned by the messagebox beep. Try the program and you should hear the cash register sound each time you win (ask Mr. W for headphones if you can't get your computer's speaker to work).

A little brain-teaser for you: if you were to click the lblSpin label at one second to midnight, the numbers would never stop spinning - can you explain why?

Previous Up Next