Section 7.15. Case Study: Random Number Generation


7.15. Case Study: Random Number Generation

We now take a brief and hopefully entertaining diversion into a popular programming applicationsimulation and game playing. In this and the next section, we develop a game-playing program with multiple methods. The program employs many of the control statements presented thus far in the book and introduces several new concepts.

There is something in the air of a gambling casino that invigorates peoplefrom the high rollers at the plush mahogany-and-felt craps tables to the quarter poppers at the one-armed bandits. It is the element of chance, the possibility that luck will convert a pocketful of money into a mountain of wealth. Unfortunately, that rarely happens because the odds, of course, favor the casinos. The element of chance can be introduced through class Random (located in namespace System).

Class Random and Method Next

Consider the following statements:

 Dim randomObject As New Random() Dim randomNumber As Integer = randomObject.Next() 


The first statement declares randomObject as a reference to an object of type Random and creates a new Random object.

The second statement declares Integer variable randomNumber and assigns to it the value returned by calling Random method Next. Method Next generates a positive Integer value greater than or equal to zero and less than the constant Int32.MaxValue (2,147,483,647). If Next truly produces values at random, every value in this range has an equal chance (or probability) of being chosen when Next is called. The values returned by Next are actually pseudo-random numbers, or a sequence of values produced by a complex mathematical calculation. This calculation requires a seed value. If the seed value is different each time the program is run, the series of values will be different as well (so that the generated numbers are indeed random). When we create a Random object, the seed is based on the current time. Alternatively, we can pass a seed value as an argument in the parentheses after New Random. Passing in the same seed twice results in the same series of random numbers. Using the current time of day as the seed value is effective because the time is likely to change for each Random object we create.

The range of values produced by Next is often different from what is needed in a particular application. For example, a program that simulates coin-tossing might require only 0 for "heads" and 1 for "tails." A program that simulates the rolling of a six-sided die would require random integers in the range 16. Similarly, a program that randomly predicts the next type of spaceship (out of four possibilities) that flies across the horizon in a video game might require random integers from 1 to 4.

Scaling and Shifting of Random Numbers

By passing an argument to method Next as follows

 value = 1 + randomObject.Next(6) 


we can produce integers in the range 16. When a single argument is passed to Next, the values returned by Next will be in the range from 0 to (but not including) the value of that argument. This is called scaling. The number 6 is the scaling factor. We shift the range of numbers produced by adding 1 to our previous result, so that the return values are between 1 and 6 rather than 0 and 5.

Visual Basic simplifies the process of specifying a range of random numbers by allowing you to pass two arguments to Next. For example, the preceding statement also could be written as

 value = randomObject.Next(1, 7) 


Note that we must use 7 as the second argument to method Next to produce integers in the range from 1 to 6. The first argument indicates the minimum value in our desired range, whereas the second is equal to 1 + the maximum value desired. Fig. 7.13 demonstrates the use of class Random and method Next by simulating 20 rolls of a six-sided die and showing the value of each roll. Note that all the values are in the range from 1 to 6, inclusive.

Figure 7.13. Random integers from 1 to 6 created by calling method Next of class Random.

  1  ' Fig. 7.13: RandomInteger.vb  2  ' Generating random integers.  3  Module RandomInteger  4     Sub Main()  5        Dim randomObject As New Random()  ' create  Random object  6        Dim randomNumber As Integer  7  8        ' generate 20 random numbers between 1 and 6  9        For i As Integer = 1 To 20 10           randomNumber = randomObject.Next(1, 7) 11           Console.Write(randomNumber & " ") 12 13           If i Mod 5 = 0 Then ' is i a multiple of 5? 14              Console.WriteLine() 15           End If 16        Next 17     End Sub ' Main 18  End Module ' RandomInteger 

1 1 3 1 1 2 1 1 3 6 6 3 4 6 6 2 2 3 6 5 



The program in Fig. 7.14 uses class Random to simulate rolling four six-sided dice. We then use some of the functionality from this program in another example (Fig. 7.16) to demonstrate that the numbers generated by Next occur with approximately equal likelihood.

Figure 7.14. Demonstrating four die rolls with graphical output.

  1  ' Fig. 7.14: RollDice.vb  2  ' Rolling four dice.  3  Imports System.IO  4  5  Public Class FrmRollDice  6     ' declare Random object reference  7     Dim randomObject As New Random()   8  9     ' display results of four rolls 10     Private Sub btnRoll_Click(ByVal sender As System.Object, _ 11        ByVal e As System.EventArgs) Handles btnRoll.Click 12        ' method randomly assigns a face to each die 13        DisplayDie(picDie1) 14        DisplayDie(picDie2) 15        DisplayDie(picDie3) 16        DisplayDie(picDie4) 17     End Sub ' btnRoll_Click 18 19     ' get a random  die image 20     Sub DisplayDie(ByVal picDie As PictureBox) 21        ' generate random integer in range 1 to 6     22        Dim face As Integer = randomObject.Next(1, 7) 23 24        ' load corresponding image                                        25        picDie.Image = Image.FromFile( _                                  26           Directory.GetCurrentDirectory & "\Images\die" & face & ".png") 27     End Sub ' DisplayDie 28  End Class ' FrmRollDice 

(a)

(b)

Using Buttons on a GUI

Before we discuss the use of Random in this application, let us analyze the GUI controls we use and the flow of control in this example. The names of the GUI controls are indicated in the output of Fig. 7.14. In this example, we use four PictureBoxes. You used PictureBoxes in Chapters 2 and 5. In these examples, you used the PictureBox's Image property to display an image. We will do the same, but set the control's Image property programmatically, so that different die images can be displayed based on the random numbers generated.

In this example, we also use our first Button control. Like the other controls we have used, the Button control can be simply dragged and dropped onto the Form from the Toolbox, and its sizing handles can be used to increase or decrease the size of the Button. The Text property of the Button has been set to Roll and the font size of the Button's text has been set to 12, using the same Font dialog as you would for Label controls. Name the control btnRoll. Recall that we have used prefixes for our other controls, to make identifying the type of control easier during coding. For Buttons, we will use the btn prefix.

Creating a Click Event Handler

For this example, the random die images will be displayed whenever btnRoll is clicked. To enable such functionality, we need to add an event handler for our Button's Click event. To do so, simply double click the Button in design view. This will create the empty event handler in your code. In Chapter 5 we created an event handler for the Form's Load event, which is executed when the Form is loaded. An event handler for a Button's Click event executes whenever the Button is clicked. The event handler with code added to its body is defined in lines 1017. The name of the event handler is btnRoll_Click. Note that the event handler is a subroutinethe event handler performs actions in response to an event, but does not return a value. The first argument to this method represents the object that is associated with the event; the second argument is an object that contains information about the event. Event-handler names created by the IDE normally begin with the object's name, followed by an underscore and the name of the event. From here on, if you see a method in an example named using this convention, you can assume that it is an event handler. Event handlers are discussed in more detail in Chapter 13.

Displaying Random Images in a PictureBox

The body of our event handler calls method DisplayDie four times, once for each PictureBox on the Form. Calling DisplayDie (lines 1316) causes four dice to appear as if they are being rolled each time Roll is clicked. When this program runs, the dice images do not appear until the user clicks Roll for the first time.

Method DisplayDie specifies the correct image for the face value calculated by method Next (line 22). Note that we declare randomObject as an instance variable of FrmRollDice (line 7). This allows the same Random object to be used each time DisplayDie executes. We set the Image property (line 25) to display one of the die images (the image is selected using random values) in the current PictureBox (passed as an argument). We set the property's value with an assignment statement (lines 2526). Note that we specify the image to display through method FromFile in class Image (contained in the System.Drawing namespace). Method GetCurrentDirectory of class Directory (contained in the System.IO namespace) returns the current directory. Recall that when the application is compiled, an executable (.exe file) is created. This is the file that is executed when the application is run, so GetCurrentDirectory returns the location of this file. It is important to note that there are actually two .exe files createdone to execute when the application is run with debugging (located in the application's bin\Debug directory), and one to execute when the application is run without debugging (located in the application's bin\Release directory). Therefore, method GetCurrentDirectory can return different values based on how you run the application. We have added the images to both directories so that the application will run correctly with and without debugging. The graphics used in this example are located in the example's project directory. The examples for this book are available at www.deitel.com/books/vbforprogrammers2.

Importing a Namespace for an Entire Project

We include an Imports statement (line 3) for the namespace System.IO but not for System.Drawing. By default, Windows applications import several namespaces, including System, System.Drawing, and System.Windows.Forms. These namespaces are imported for the entire project, eliminating the need for Imports statements in individual project files. You can see which namespaces have been imported into a project by double clicking the My Project folder in the Solution Explorer, and then selecting References in the page that appears. You will be presented with a list of the application's references to assemblies in the References area of the window, and a list of the namespaces defined in those references in the Imported namespaces area (Fig. 7.15). The namespaces that have been checked are those that are imported for the entire project. Some of the namespaces imported by default are not used in this example. For instance, we do not yet use namespace System.Collections, which allows you to create collections of objects (see Chapter 26, Collections). Do not confuse importing namespaces for an entire application with adding references to an application. Adding a reference to an application causes a library (.dll) file to be included into your application. This compiled code can contain several namespaces. An Imports statement indicates that you will be using a specific namespace from a library file.

Figure 7.15. Imported namespaces in a project.


The Windows application in Fig. 7.16 enables the reader to repeatedly roll 12 dice to show that the numbers generated by class Random occur with approximately equal frequencies. The program displays the cumulative frequencies of each face in a TextBox control, and the die faces are displayed using 12 PictureBoxes.

Figure 7.16. Random class used to simulate rolling 12 six-sided dice.

  1  ' Fig. 7.16: RollTwelveDice.vb  2  ' Rolling 12 dice with  frequency chart.  3  Imports System.IO  4  5  Public Class FrmRollTwelveDice  6     Dim randomObject As New Random()  ' generate random number  7     Dim ones As Integer  ' count of  die face 1  8     Dim twos As Integer  ' count of  die face 2  9     Dim threes As Integer  ' count of die face 3 10     Dim fours As Integer ' count of die face 4 11     Dim fives As Integer ' count of die face 5 12     Dim sixes As Integer ' count of die face 6 13 14     ' display result of twelve rolls 15     Private Sub btnRoll_Click(ByVal sender As System.Object, _ 16        ByVal e As  System.EventArgs) Handles btnRoll.Click 17 18        ' assign random faces to 12 dice using DisplayDiex1 19        DisplayDie(picDie1) 20        DisplayDie(picDie2) 21        DisplayDie(picDie3) 22        DisplayDie(picDie4) 23        DisplayDie(picDie5) 24        DisplayDie(picDie6) 25        DisplayDie(picDie7) 26        DisplayDie(picDie8) 27        DisplayDie(picDie9) 28        DisplayDie(picDie10) 29        DisplayDie(picDie11) 30        DisplayDie(picDie12) 31 32        Dim total As Integer = ones + twos + threes +  fours + fives + sixes 33        Dim output As String 34 35        ' display frequencies of faces 36        output = ("Face" & vbTab & vbTab & "Frequency" & vbTab & "Percent") 37        output &= (vbCrLf & "1" & vbTab & vbTab & ones & _ 38           vbTab & vbTab & String.Format("{0:P}", ones / total)) 39        output &= (vbCrLf & "2" & vbTab & vbTab & twos & vbTab & _ 40           vbTab & String.Format("{0:P}", twos / total)) 41        output &= (vbCrLf & "3" & vbTab & vbTab & threes & vbTab & _ 42           vbTab & String.Format("{0:P}", threes / total)) 43        output &= (vbCrLf & "4" & vbTab & vbTab & fours & vbTab & _ 44           vbTab & String.Format("{0:P}", fours / total)) 45        output &= (vbCrLf & "5" & vbTab & vbTab & fives & vbTab & _ 46           vbTab & String.Format("{0:P}", fives / total)) 47        output &= (vbCrLf & "6" & vbTab & vbTab & sixes & vbTab & _ 48           vbTab & String.Format("{0:P}", sixes / total) & vbCrLf) 49        txtDisplay.Text = output 50     End Sub ' btnRoll_Click 51 52     ' display a single die image 53     Sub DisplayDie(ByVal picDie As PictureBox) 54        Dim face As Integer = randomObject.Next(1, 7) 55 56        picDie.Image = Image.FromFile(Directory.GetCurrentDirectory & _ 57           "\Images\die" & face & ".png") 58 59        ' maintain count of die faces 60        Select Case face 61           Case 1  ' die face 1 62              ones += 1 63           Case 2  ' die face 2 64              twos += 1 65           Case 3  ' die face 3 66              threes += 1 67           Case 4  ' die face 4 68              fours += 1 69           Case 5  ' die face 5 70              fives += 1 71           Case 6  ' die face 6 72              sixes += 1 73        End Select 74     End Sub  ' DisplayDie 75  End Class  ' FrmRollTwelveDice 

The TextBox control is located toward the bottom of the GUI. This control can be used both for displaying data to the user and inputting data from the user. The data in the TextBox can be accessed and modified via the control's Text property. This TextBox's name is txTDisplay (we use the txt prefix for TextBoxes) and the font size has been set to 9. Finally, the TextBox's Multiline property has been set to true, so that multiple lines of text can be displayed.

Fig. 7.16 contains two screenshots. The one on the left shows the program when it initially executes, and the one on the right shows the program after the user has clicked Roll over 200 times. If the values produced by method Next are indeed random, the frequencies of the face values (16) should be approximately the same (as Fig. 7.16(b) illustrates).

To show that the die rolls occur with approximately equal likelihood, the program in Fig. 7.16 has been modified to keep some simple statistics. We declare counters for each of the possible rolls in lines 712. Note that the counters are instance variables. Lines 3749 display the frequency of each roll as percentages using the P format specifier.

As the program output demonstrates, method Next can be used to effectively simulate the rolling of a six-sided die. Over the course of many die rolls, each of the possible faces from 16 appears with equal likelihood, or approximately one-sixth of the time. Note that no Case Else is provided in the Select...Case statement (lines 6073), because we know that the values generated are in the range 16. In Chapter 8, Arrays, we show the power of arrays by explaining how to replace the entire Select...Case statement in this program with a single-line statement.

Run the program several times and observe the results. Note that a different sequence of random numbers is obtained each time the program is executed, causing the resulting frequencies to vary.



Visual BasicR 2005 for Programmers. DeitelR Developer Series
Visual Basic 2005 for Programmers (2nd Edition)
ISBN: 013225140X
EAN: 2147483647
Year: 2004
Pages: 435

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net