| 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:
 | variable arrays |
 | For...Next loops |
 | the relationship between numbers and the conditions 'true' and 'false' |
 | random 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...
 | modify the checkwin code so that the user can also win by getting two
digits that are the same |
 | increase 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 |
 | add new features that you have thought of yourself |
 | add 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? |