Using Procedures to Organize Scripts
Overview
By now you've seen and worked on a number of VBScript projects in this book, and all of these scripts have been organized the same way. First you've set up script initialization processes (defining variables, constants, objects, and so on), and then you sequentially wrote the rest of the script as one big collection of statements. You've then used the If and Select Case statements to organize your scripts. Finally, by embedding statements within one another you have further refined your scripts' organization. In this chapter, you will learn how to further improve the organization of your VBScripts, using procedures. Specifically, you will learn how to
- Create your own customized functions
- Create reusable collections of statements using subroutines
- Break scripts down into modules of code to make them easier to manage
- Control variable scope within your scripts using procedures
Project Preview The BlackJack Lite Game
In this chapter, you will learn how to create a game called BlackJack Lite. This game is based on the classic BlackJack game played in casinos around the world. In this game, both the player and the computer will be dealt a single card, face up. The object of the game is to try to get as close as possible to a value of 21 without going over. The player can ask for as many extra cards (hits) as desired and can stop (rest) at any time. If the player goes over 21, he or she busts. Otherwise, the computer plays its hand, stopping only after either reaching a total of 17 or more or busting. Figures 7.1 through 7.5 demonstrate the game in action.
Figure 7.1: The game's splash screen invites the user to play a game of BlackJack Lite.
Figure 7.2: If the user declines, the game displays information about itself and its author and invites the user to play later.
Figure 7.3: If the user accepts the offer to play, the initial hands are dealt.
Figure 7.4: The user plays until either busting or holding.
Figure 7.5: The computer then plays and the results of the game are shown.
By the time you've worked your way though this chapter and completed the BlackJack Lite game, you will have gained a solid understanding of how to use procedures. You will be able to improve the overall organization and functionality of your VBScripts and will be prepared to tackle even more challenging projects.
Improving Script Design with Procedures
VBScript procedures improve the overall organization and readability of scripts giving you a way to group related statements together and execute them as a unit. Once written, a VBScript procedure can be called on from any location in your script and can be executed over and over again as needed. This allows you to create scripts that are smaller and easier to maintain.
Definition
A procedure is simply a collection of VBScript statements that, when called, are executed as a unit.
VBScript provides support for two different types of procedures:
- Sub. A VBScript procedure that executes a set of statements without returning a result.
- Function. A VBScript procedure that executes a set of statements and, optionally, returns a result to the statement that called it.
TRICK |
I recommend using procedures as the primary organization tool for all VBScripts. By organizing a script into procedures, you break it down into a collection of units. This allows you to separate processes from one another, making it easier to develop scripts in a modular fashion, one component at a time. |
Introducing Subroutines
The VBScript Sub procedure is used to create subroutines. Subroutines are great for grouping together statements that perform a common task from which a result is not required. When called, subroutines execute their statements and then return processing control back to the calling statement.
The syntax for this type of procedures is as follows:
[Public | Private] Sub name [(arglist)] statements End Sub
Private is an optional keyword that specifies that the subroutine cannot be called by other procedures within the script, thus limiting the ability to reference it. Public is an optional keyword that specifies that the subroutine can be called by other procedures within the script. Name is the name assigned to the subroutine. Like variables, a subroutine's name must be unique within the script that defines it. Arglist represents a list of one or more comma-separated arguments that can be passed to the subroutine for processing, and statements represents the statements that make up the subroutine.
For example, the next subroutines is called DisplaySplashScreen(). It does not accept any arguments and it does not return anything back to the VBScript statement that calls it. What it does do is display a script's splash screen any time it is called.
Sub DisplaySplashScreen() MsgBox "Thank you for playing the game. Jerry Ford 2002." & _ vbCrLf & vbCrLf & "Please play again soon!", 4144, "Test Game" End Sub
You can execute this subroutine by calling it from anywhere within your script using the following statement:
DisplaySplashScreen()
The following example is a rewrite of the previous subroutine; only this time the subroutine has been rewritten to accept an argument. The argument passed to the subroutine will be a message. Using a subroutine in this manner, you can develop scripts that display all their popup dialogs using one subroutine.
Sub DisplaySplashScreen(Message) MsgBox Message, 4144, "Test Game" End Sub
You can call this subroutine from anywhere within your script like this:
DisplaySplashScreen("Thank you for playing the game. Jerry Ford 2002." &_ vbCrLf & vbCrLf & "Please play again soon!")
Creating Custom Functions
Functions are almost exactly like subroutines. Functions can do anything that a subroutine can do. In addition, a function can return a result back to the statement that called it. As a result (to keep things simple), I usually use functions only within my VBScripts.
The syntax for a function is as follows:
[Public | Private] Function name [(arglist)] statements End Function
Private is an optional keyword that specifies that the function cannot be called by other procedures within the script, thus limiting the ability to reference it. Public is an optional keyword that specifies that the function can be called by other procedures within the script. Name is the name assigned to the function. Like variables, a function's name must be unique within the script that defines it. Arglist represents a list of one or more comma-separated arguments that can be passed to the function for processing, and statements represents the statements that make up the function.
Let's look at an example of a function that does not return a result to its calling statement.
Function DisplaySplashScreen() MsgBox "Thank you for playing the game. Jerry Ford 2002." & _ vbCrLf & vbCrLf & "Please play again soon!", 4144, "Test Game" End Function
As written, this function performs the exact same operation as the subroutine you saw previously. This function can be called from anywhere in your script using the following statement:
DisplaySplashScreen()
As with subroutines, you may pass any number of arguments to your functions, as long as commas separate the arguments, like this:
Function DisplaySplashScreen(Message) MsgBox Message, 4144, "Test Game" End Function
Once again, this function is no different from the corresponding subroutine example you just saw, and can be called as follows:
DisplaySplashScreen("Thank you for playing the game. Jerry Ford 2002." &_ vbCrLf & vbCrLf & "Please play again soon!")
Functions can also be set up to return a result to their calling statement. This is achieved by creating a variable within the function that has the same name as the function, and by setting the variable equal to the result that you want the function to return.
Again, this technique can best be demonstrated with an example.
PlayersName = GetPlayersName() MsgBox "Greetings " & PlayersName Function GetPlayersName() GetPlayersName = InputBox("What is your first name?") End Function
The first statement calls a function name GetPlayersName(). The second statement displays the results returned by the function and stored in the variable called PlayersName. The next three lines are the actual function, which consists of a single statement that collects the player's name and assigns it to a variable named GetPlayersName so that it can be passed back to the calling statement.
Another way to call a function is to reference it as part of another VBScript statement, like this:
MsgBox "Greeting " & GetPlayersName()
Improving Script Manageability
As I said before, by organizing your VBScripts into procedures, you make them more manageable, allowing you to create larger and more complex scripts without adding mounds of complexity. As an example, let's say that you're developing a game that performs the five major activities that follow:
- Initializes variables, constants, and objects used by the script
- Asks the player if he or she wants to play the game
- Collects the player's name
- Displays a story, substituting the player's name at predetermined locations within the story
- Displays a closing dialog inviting the player to play again on another day
One way to design your script would be to first define the variables, constants, and object references, and then create a series of functions and subroutine calls from the script's main processing section. The rest of the script would then consist of individual functions and subroutines, each of which would be designed to perform one of the activities outlined in the previous list.
Writing Reusable Code
One of the biggest advantages provided by functions and subroutines is the ability to create reusable code within your VBScripts. Any time you find yourself needing to perform the same task over and over in a script—such as displaying messages in popup dialogs or retrieving random numbers—consider creating a function or subroutine. Then, by using a single statement to call the appropriate procedure, you can reuse the statements located within the procedure over and over again.
Functions and subroutines help make for smaller scripts. They also make script maintenance and enhancement much easier and quicker. For example, it's a lot easier to change one line of code located in a procedure than it is to make that same change in numerous places throughout a script.
IN THE REAL WORLD
Once sign of a world-class programmer is the path that he or she leaves behind— in other words, the professional way in which the programmer organizes and documents his or her scripts. One organizational technique used by experienced programmers is to group all functions and subroutines together in one place, apart from the initialization and main processing sections of the script. This makes them easy to locate and maintain. Usually, you'll find a script's functions and subroutines located at the bottom of the script. I suggest that you modify your script template to include a Procedure section for this purpose.
The Guess a Number Game Revisited
So far, you have seen examples of small pieces of code that work with functions and subroutines. Now let's take a look at how to apply procedures to a larger script. To begin, take a moment to go back and review the Guess a Number game at the end of Chapter 6. This script, like all other scripts in this book prior to this chapter, was written without the use of procedures.
As I deliberately avoided using procedures in the script from Chapter 6, I had to use other techniques for organizing the script's programming logic. What I chose to do was put everything in the script's main processing section as follows:
- Added statements that generate a random number
- Added a Do...Until loop that controls the game's execution
- Embedded an If statement within the Do...Until loop that ensures that the player typed a number
- Embedded a second If statement within the previous If statement that makes sure that the data the player typed was numeric
- Embedded three more If statements within the previous If statement in order determine whether the player's guess was low, high, or correct
As you can see, I had to embed a lot of statements within one another in order to organize the script into a workable game. As the script itself was not exceptionally large, this was a manageable task. However, had the script been much larger or more complex, it would have been difficult to keep track of all the embedded logic.
Now that you understand what procedures are and what they're used for, let's take a moment and go back and redesign the Guess a Number game using them. One way of doing this is as follows:
'************************************************************************* 'Script Name: GuessANumber-2.vbs 'Author: Jerry Ford 'Created: 11/29/02 'Description: This script plays a number-guessing game with the user '************************************************************************* 'Initialization Section Option Explicit Const cGreetingMsg = "Pick a number between 1 - 100" Dim UserNumber, RandomNo, OkToEnd, NoGuesses, BadData OkToEnd = "no" NoGuesses = 0 'Main processing Section RandomNumber() 'Get the game's random number PlayTheGame() 'Start the game WScript.Quit() 'End the game 'Procedure Section 'Generate the game's random number Function RandomNumber() 'Generate a random number Randomize RandomNo = FormatNumber(Int((100 * Rnd) + 1)) End Function 'Set up a Do...Until loop to control the execution of the game Function PlayTheGame() 'Loop until either the user guesses correctly or the user clicks on Cancel Do Until OkToEnd = "yes" 'Prompt user to pick a number UserNumber = InputBox("Type your guess:", cGreetingMsg) NoGuesses = NoGuesses + 1 BadData = "no" 'Go see if there is anything wrong with the player's input ValidateInput() If OkToEnd <> "yes" Then 'The player typed in something If BadData <> "yes" Then 'The player typed in a number TestAnswer() 'Let's see how good the player's guess was End If End If Loop End Function 'Determine if there are any problems with the data entered by the player Function ValidateInput() 'See if the player provided an answer If Len(UserNumber) = 0 Then MsgBox "You either failed to type a value or you clicked on Cancel. " & _ "Please play again soon!", , cGreetingMsg OkToEnd = "yes" Else 'Make sure that the player typed a number If IsNumeric(UserNumber) = False Then MsgBox "Sorry. You did not enter a number. Try again.", , cGreetingMsg BadData = "yes" End If End If End Function 'Determine if the player's guess is too low, too high, or just right Function TestAnswer() 'Test to see if the user's guess was correct If FormatNumber(UserNumber) = RandomNo Then MsgBox "Congratulations! You guessed it. The number was " & _ UserNumber & "." & vbCrLf & vbCrLf & "You guessed it " & _ "in " & NoGuesses & " guesses.", ,cGreetingMsg OkToEnd = "yes" End If 'Test to see if the user's guess was too low If FormatNumber(UserNumber) < RandomNo Then MsgBox "Your guess was too low. Try again", ,cGreetingMsg OkToEnd = "no" End If 'Test to see if the user's guess was too high If FormatNumber(UserNumber) > RandomNo Then MsgBox "Your guess was too high. Try again", ,cGreetingMsg OkToEnd = "no" End If End Function
As you can see, the script's initialization section remained unchanged, except for the addition of one more variable, which will be used to indicate that the player has typed an invalid character. However, the main processing section is now quite different. Instead of having all of the script's statements embedded within it, this section now drives the script by maintaining high-level control over a collection of functions, each of which performs a specific process for the script.
The main processing section now does three things: It calls a function that gets the game's random number (RandomNumber()), it calls a function that controls the play of the game (PlayTheGame()), and then it ends the game by executing the WScript object's Quit() method.
The RandomNumber() function generates the random number used by the game. The PlayTheGame() function controls play of the game itself. Instead of making this a really large function, I simplified it a bit by removing and modifying the two If statements that perform input validation and placing them within their own function called ValidInput(). Likewise, I moved and modified the three If statements that determine if the player's guess was low, high, or correct into their own function, called TestAnswer(). The only other modification made to the script was the addition of the following statements in the PlayTheGame() function:
If OkToEnd <> "yes" Then 'The player typed in something If BadData <> "yes" Then 'The player typed in a number TestAnswer() 'Let's see how good the player's guess was End If End If
These statements were needed to test the values of variables manipulated in the ValidateInput() and TestAnswer() functions.
Working with Built in VBScript Functions
VBScript provides a large collection of built-in functions that you can add to your scripts to save yourself time and effort. Obviously, leveraging the convenience and power of these built-in VBScript functions is a smart thing to do.
In fact, VBScript's built-in functions are so essential to VBScript development that it's difficult to write a script of any complexity without using them. I have already demonstrated this fact many times throughout the book. A complete list of all VBScript built-in functions appears in Appendix B, "Built-In VBScript Functions."
Limiting Variable Scope with Procedures
You have seen and worked with variables throughout this book. Thus far, all the variables that you have worked with have had a global or script-level scope, meaning they could be accessed from any point within the script. Any variable that is defined outside of a VBScript procedure (that is, function or subroutine) is global in scope.
In contrast, any variable defined within a procedure is local in scope, meaning it exists and can only be referenced within the procedure that defines it. The best way to demonstrate the concept of global and local variable scope is in an example. The following script creates two variables, one at the beginning of the script and the other within a function:
Option Explicit Dim FirstRandomNumber FirstRandomNumber = GetRandomNumber() MsgBox "The first random number is " & FirstRandomNumber GenerateLocalizedVariable() MsgBox "The second random number is " & SecondRandomNumber WScript.Quit() Function GenerateLocalizedVariable() Dim SecondRandomNumber SecondRandomNumber = GetRandomNumber() MsgBox "The second random number is " & SecondRandomNumber End Function Function GetRandomNumber() 'Generate a random number between 1 and 10 Randomize GetRandomNumber = FormatNumber(Int((10 * Rnd) + 1)) End Function
When you run this script, the first variable is defined at the beginning of the script, making it a global variable. The value of the variable is then immediately displayed. The second variable is defined within a function named GenerateLocalizedVariable(). As a result, the variable can be referenced only within this function, as proven when the function's MsgBox() statement displays its value. When the GenerateLocalizedVariable() function completes its execution, processing control returns to the statement that called the function. This statement is immediately following by another MsgBox() statement, which attempts to display the value of the variable defined in the GenerateLocalizedVariable() function. However, this variable was destroyed as soon as that function ended, so instead of seeing the variable's value, an error message is displayed, as shown in Figure 7.6.
Figure 7.6: Attempting to access a localized variable outside of the procedure that defined its results in an error.
Back to the BlackJack Lite Game
Now let's return to the development of the BlackJack Lite game. In this game, you'll develop your own version of the casino game BlackJack. BlackJack Lite is a card game that pits the player against the computer. The object of the game is to come as close to 21 as possible without going over, in order to beat the computer's hand. The computer, like a real casino BlackJack dealer, waits for the player to finish before playing. The computer must then take hits until its hand busts (goes over 21) or reaches at least 17, at which time it must stop.
Designing the Game
The BlackJack Lite game is more complex than the other VBScripts that you've seen in this book. The game itself has a large number of different functions to perform. For example, the initial hand must be dealt for both the player and the computer. Then the game has to facilitate the dealing of cards to the player and later to the computer. In addition, numerous smaller processes must occur along the way.
Because this script is rather complex, I've decided to organize it into procedures. Each procedure will be assigned a specific activity to perform. As part of my preparation for the design of the game, I have drawn a high-level flowchart of the game's overall structure and processing logic; the flowchart is shown in Figure 7.7.
Figure 7.7: A flowchart outlining the overall design and execution flow of the BlackJack Lite game
The script will consist of eight functions. These functions and their basic purpose are as follows:
- DoYouWantToPlay(). Displays the game's splash screen and invites the user to play the game.
- NowGoPlay(). Controls the overall execution of the game, calling upon other procedures as required.
- DealFirstHand(). Presents the initial cards for both the player and the computer.
- PlayTheGame(). Asks the player if he or she would like another card and determines when the player has either busted or decided to hold.
- GetRandomNumber(). This function is called by several other functions in the script. It returns a random number between 1 and 13 representing the value of a playing card.
- ComputerPlay(). Plays the computer hand, taking hits until either the computer's hand is busted or is greater than 17.
- DetermineWinner(). Compares the player's hand against the computer's hand to determine who has won. It then offers to let the player play another hand. If the player accepts, the NowGoPlay() function is called, starting a new hand.
- DisplaySplashScreen(). Displays information about the game and its author, and invites the player to return and play again before finally ending the game.
Setting up the Initialization Section
Begin the development of the BlackJack Lite game the same way that you've begun all your other games, by first creating a new file and adding in your VBScript template, and then setting up the variables, constants, and object references in the script's Initialization Section.
'************************************************************************* 'Script Name: BlackJack.vbs 'Author: Jerry Ford 'Created: 11/28/02 'Description: This script creates a scaled down version of the casino 'version of the BlackJack card game '************************************************************************* 'Initialization Section Option Explicit Dim PlayGame, CardImage, UserCard, ComputerCard, AnotherCard, UserNextCard Dim UserDone, NewComputerCard, PlayAgain, UserBusted, TextMsg UserDone = "False" UserBusted = "False"
This game is fairly lengthy and requires a number of variables.
- PlayGame. Stores the player's reply when asked if he or she wants to play a game.
- CardImage. Stores the message displayed in the game's initial popup dialog.
- UserCard. Stores the total value of the cards dealt to the user.
- ComputerCard. Stores the total value of the cards dealt to the computer.
- AnotherCard. Stores the player's reply to the question of whether he or she wants another card.
- UserNextCard. Stores the value returned by the function that retrieves a random number and is later added to the value of the UserCard variable.
- UserDone. Stores a value indicating whether the player is ready to hold.
- NewComputerCard. Stores the value returned by the function that retrieves a random number and is later added to the value of the ComputerCard variable.
- PlayAgain. Stores the player's reply when asked if he or she wants to play another game.
- UserBusted. Stores a value indicating whether or not the player has busted.
- TextMsg. Stores text to be displayed in popup dialogs displayed by the game.
Developing the Logic for the Main Processing Section
The script's Main Processing section is very small and consists only of a call to the DoYouWantToPlay() function to determine whether the player want to play the game, followed by the Select Case statement, which determines the player's reply.
'Main processing Section 'Ask the user if he or she wants to play PlayGame = DoYouWantToPlay() Select Case PlayGame Case 6 'User clicked on Yes NowGoPlay() Case 7 'User clicked on No DisplaySplashScreen() End Select
If the player clicks on the Yes button, then the NowGoPlay() function is called. Otherwise, the DisplaySplashScreen() function is called. This function displays a popup dialog providing information about the game and then terminates the game's execution.
Creating the DoYouWantToPlay() Function
This function displays the game's initial popup dialog and invites the player to play a game of BlackJack Lite. Much of the text displayed in this popup dialog is dedicated to creating a graphic image depicting the Ace of Spades. Also included on this popup dialog is a brief set of instructions.
function DoYouWantToPlay() CardImage = " ===============" & Space(15) & "Rules and Instructions" & _ vbCrLf & _ "| * " & Space(32) & "|" & Space(15) & "===============" & _ "========" & vbCrLf & _ "| * * " & Space(31) & "|" & Space(15) & "1. Try to get to " & _ "21 without going over." & vbCrLf & _ "| *** " & Space(31) & "|" & Space(15) & "2. Aces count as " & _ "11s (not 1s)." & vbCrLf & _ "| * * " & Space(31) & "|" & Space(15) & "3. The dealer " & _ "must stop at 17 or later." & vbCrLf & _ "|" & Space(15) & "****" & Space(16) & "|" & vbCrLf & _ "|" & Space(17) & "**" & Space(18) & "|" & vbCrLf & _ "|" & Space(14) & "* ** *" & Space(15) &"|" & vbCrLf & _ "|" & Space(11) & "********" & Space(12) &"|" & vbCrLf & _ "|" & Space(9) & "**********" & Space(10) & "|" & vbCrLf & _ "|" & Space(9) & "**********" & Space(10) & "|" & vbCrLf & _ "|" & Space(11) & "********" & Space(12) & "|" & vbCrLf & _ "|" & Space(13) & "******" & Space(14) & "|" & vbCrLf & _ "|" & Space(15) & "****" & Space(16) & "|" & vbCrLf & _ "|" & Space(17) & " *" & Space(19) & "|" & vbCrLf & _ "|" & Space(32) & "* * |" & vbCrLf & _ "|" & Space(32) & "*** |" & vbCrLf & _ "|" & Space(32) & "* * |" & vbCrLf & _ "|" & Space(33) & " * |" & vbCrLf & _ " ===============" & vbCrLf & vbCrLf & vbCrLf & vbCrLf & _ "Would you like to play a game of Blackjack Lite? " DoYouWantToPlay = MsgBox(CardImage, 36, "BlackJack Lite") End Function
If the player clicks on the Yes button, the value of DoYouWantToPlay is set to 6. This value will later be tested in the script's main processing section in order to determine if the game should continue.
Creating the NowGoPlay() Function
The NowGoPlay() function is called when the player clicks on the Yes button on the script's initial popup dialog, indicating that he or she wishes to play the game.
function NowGoPlay() DealFirstHand() PlayTheGame() If UserBusted = "False" Then ComputerPlay() End If DetermineWinner() End Function
This function controls the actual play of the game. It is made up of calls to several other functions. First it calls the DealFirstHand() function, which deals both the user and the computer their initial cards. Next it calls the PlayTheGame() function, which allows the user to continue to take hits or hold and determines whether the player busted or not. The NowGoPlay() function then checks the value of the UserBusted variable to see if the game should continue. If the user has decided to hold, then the ComputerPlay() function is called so that the computer's (or dealer's) hand can finish being dealt. Regardless of whether the user busts or the ComputerPlay() function is called, eventually control returns to the NowGoPlay() function and the DetermineWinner() function is called. This function determines the winner of the hand and gives the player an opportunity to play another hand.
Creating the DealFirstHand() Function
The DealFirstHand() function makes two calls to the GetRandomNumber() function in order to deal both the player's and the computer's initial cards.
function DealFirstHand() UserCard = GetRandomNumber() ComputerCard = GetRandomNumber() End Function
Creating the PlayTheGame() Function
The PlayTheGame() function, shown next, sets up a Do...Until loop that executes until either the player busts or decides to hold. The first statement in the loop prompts the player to decide if he or she wants another card. If the player clicks on Yes, the DealAnotherCard() function is called. The PlayTheGame() function then checks to see if the player has busted, setting the value of the UserBusted and UserDone variables if appropriate (True). If the player decides to hold and clicks on the No button, the value of UserDone is also set to True.
function PlayTheGame() Do Until UserDone = "True" AnotherCard = MsgBox("User: " & Space(8) & UserCard & vbCrLf & _ "Computer: " & ComputerCard & vbCrLf & vbCrLf & _ "[Click on YES for another card]" & vbCrLf & _ "[Click on NO to stick]", 4, "Initial Deal") Select Case AnotherCard Case 6 'User clicked on Yes 'MsgBox "You decided to take a hit." DealAnotherCard() Case 7 'User clicked on No UserDone = "True" End Select If UserCard > 21 then UserBusted = "True" UserDone = "True" End If Loop End Function
Creating the ComputerPlay() Function
The ComputerPlay() function, shown below, is responsible for dealing the computer's hand. It uses a Do...While loop to continue dealing the computer's hand until either the computer's hand exceeds a total of 17 but remains under 21, or it busts.
function ComputerPlay() Do While ComputerCard < 17 NewComputerCard = GetRandomNumber() ComputerCard = ComputerCard + NewComputerCard Loop
Inside the Do...While loop are two statements. The first statement deals the computer a new card by calling the GetRandomNumber() function. The second statement uses the value returned by the GetRandomNumber() function to update the computer's hand (that is, its total).
Creating the DetermineWinner() Function
The DetermineWinner() function, shown below, checks to see if the value of UserBusted is set to True. It also checks to see if the computer has busted, by checking to see if the value of ComputerCard is greater than 21. If either of these conditions is true, the script assigns an appropriate text message to the TextMsg variable. This variable is used as input in an InputBox() popup dialog that shows the player the results of the game. If neither of these conditions is true, the DetermineWinner() function performs three tests to determine whether the player won, the computer won, or if there was a tie; the function then sets the value of TextMsg accordingly.
function DetermineWinner() If UserBusted = "True" Then TextMsg = "The user has busted!" Else If ComputerCard > 21 then TextMsg = "The Computer has busted!" Else If UserCard > ComputerCard Then TextMsg = "The user wins!" If UserCard = ComputerCard Then TextMsg = "Push (e.g. Tie)!" If UserCard < ComputerCard Then TextMsg = "The Computer wins!" End If End If PlayAgain = MsgBox(TextMsg & vbCrLf & vbCrLf & "User: " & Space(8) & _ UserCard & vbCrLf & "Computer: " & ComputerCard & vbCrLf & vbCrLf & _ vbCrLf & "Would you like to play another game?", 4, "Initial Deal") If PlayAgain = 6 Then UserBusted = "False" UserDone = "False" NowGoPlay() End If DisplaySplashScreen() End Function
Finally, the game's results are displayed by showing the value of TextMsg and the value of the player's and the computer's final hands. The popup dialog also asks the player if he or she would like to play again. If the player clicks on the Yes button, then the NowGoPlay() function is called and the game starts over again. Otherwise, the DisplaySplashScreen() function is called and the game ends.
Creating the DisplaySplashScreen() Function
This final function displays the game's splash screen, providing a little information about the game and its creator, as well as offering an invitation to the player to return and play the game again another time.
function DisplaySplashScreen() MsgBox "Thank you for playing Blackjack Lite Jerry Ford 2002." & _ vbCrLf & vbCrLf & "Please play again soon!", 4144, "BlackJack Lite" WScript.Quit() End Function
After the displaying the splash screen in a popup dialog, the DisplaySplashScreen() function ends the game by executing the WScript Quit() method.
The Final Result
That's it. You are all done. Your fully assembled script should look as follows.
'************************************************************************* 'Script Name: BlackJack.vbs 'Author: Jerry Ford 'Created: 11/28/02 'Description: This script creates a scaled down version of the casino 'version of the BlackJack card game '************************************************************************* 'Initialization Section Option Explicit Dim PlayGame, CardImage, UserCard, ComputerCard, AnotherCard, UserNextCard Dim UserDone, NewComputerCard, PlayAgain, UserBusted, TextMsg UserDone = "False" UserBusted = "False" 'Main processing Section 'Ask the user if he or she wants to play PlayGame = DoYouWantToPlay() Select Case PlayGame Case 6 'User clicked on Yes NowGoPlay() Case 7 'User clicked on No DisplaySplashScreen() End Select 'Procedure Section function DoYouWantToPlay() CardImage = " ================" & Space(15) & "Rules and Instructions" & _ vbCrLf & _ "| * " & Space(32) & "|" & Space(15) & "================" & _ "========" & vbCrLf & _ "| * * " & Space(31) & "|" & Space(15) & "1. Try to get to " & _ "21 without going over." & vbCrLf & _ "| *** " & Space(31) & "|" & Space(15) & "2. Aces count as " & _ "11s (not 1s)." & vbCrLf & _ "| * * " & Space(31) & "|" & Space(15) & "3. The dealer " & _ "must stop at 17 or later." & vbCrLf & _ "|" & Space(15) & "****" & Space(16) & "|" & vbCrLf & _ "|" & Space(17) & "**" & Space(18) & "|" & vbCrLf & _ "|" & Space(14) & "* ** *" & Space(15) &"|" & vbCrLf & _ "|" & Space(11) & "********" & Space(12) &"|" & vbCrLf & _ "|" & Space(9) & "**********" & Space(10) & "|" & vbCrLf & _ "|" & Space(9) & "**********" & Space(10) & "|" & vbCrLf & _ "|" & Space(11) & "********" & Space(12) & "|" & vbCrLf & _ "|" & Space(13) & "******" & Space(14) & "|" & vbCrLf & _ "|" & Space(15) & "****" & Space(16) & "|" & vbCrLf & _ "|" & Space(17) & " *" & Space(19) & "|" & vbCrLf & _ "|" & Space(32) & "* * |" & vbCrLf & _ "|" & Space(32) & "*** |" & vbCrLf & _ "|" & Space(32) & "* * |" & vbCrLf & _ "|" & Space(33) & " * |" & vbCrLf & _ " ===============" & vbCrLf & vbCrLf & vbCrLf & vbCrLf & _ "Would you like to play a game of Blackjack Lite? " DoYouWantToPlay = MsgBox(CardImage, 36, "BlackJack Lite") End Function function NowGoPlay() DealFirstHand() PlayTheGame() If UserBusted = "False" Then ComputerPlay() End If DetermineWinner() End Function function DealFirstHand() UserCard = GetRandomNumber() ComputerCard = GetRandomNumber() End Function function PlayTheGame() Do Until UserDone = "True" AnotherCard = MsgBox("User: " & Space(8) & UserCard & vbCrLf & _ "Computer: " & ComputerCard & vbCrLf & vbCrLf & _ "[Click on YES for another card]" & vbCrLf & _ "[Click on NO to stick]", 4, "Initial Deal") Select Case AnotherCard Case 6 'User clicked on Yes 'MsgBox "You decided to take a hit." DealAnotherCard() Case 7 'User clicked on No UserDone = "True" End Select If UserCard > 21 then UserBusted = "True" UserDone = "True" End If Loop End Function function GetRandomNumber() Randomize GetRandomNumber = Round(FormatNumber(Int((13 * Rnd) + 1))) If GetRandomNumber = 1 then GetRandomNumber = 11 If GetRandomNumber > 10 then GetRandomNumber = 10 End Function function DealAnotherCard() UserNextCard = GetRandomNumber() UserCard = UserCard + UserNextCard End Function function ComputerPlay() Do While ComputerCard < 17 NewComputerCard = GetRandomNumber() ComputerCard = ComputerCard + NewComputerCard Loop End Function function DetermineWinner() If UserBusted = "True" Then TextMsg = "The user has busted!" Else If ComputerCard > 21 then TextMsg = "The Computer has busted!" Else If UserCard > ComputerCard Then TextMsg = "The user wins!" If UserCard = ComputerCard Then TextMsg = "Push (e.g. Tie)!" If UserCard < ComputerCard Then TextMsg = "The Computer wins!" End If End If PlayAgain = MsgBox(TextMsg & vbCrLf & vbCrLf & "User: " & Space(8) & _ UserCard & vbCrLf & "Computer: " & ComputerCard & vbCrLf & vbCrLf & _ vbCrLf & "Would you like to play another game?", 4, "Initial Deal") If PlayAgain = 6 Then UserBusted = "False" UserDone = "False" NowGoPlay() End If DisplaySplashScreen() End Function function DisplaySplashScreen() MsgBox "Thank you for playing Blackjack Lite Jerry Ford 2002." & _ vbCrLf & vbCrLf & "Please play again soon!", 4144, "BlackJack Lite" WScript.Quit() End Function
Take a few minutes to double-check all your work and then give this game a whirl. This is a pretty big script, so you may have to fix a few syntax errors introduced by typos you may have made when keying in the script. Once everything is working correctly, you should have a really cool game to share with and impress all your friends!
Summary
In this chapter you learned how to use procedures to streamline the organization of your VBScripts, allowing you to develop larger and more complex scripts, and, of course, games. In addition, you learned how to create reusable units of code, allowing you to make your scripts smaller and easier to mange. Finally, you learned how to control variable scope by localizing variables within procedures.
Challenges
- Give the BlackJack Lite game's splash screen a more polished look by providing additional information in the Rules and Instructions section of the dialog.
- Improve the BlackJack Lite game by adding logic to include the selection of the card's type (Club, Heart, Spade, or Diamond).
- Once you have modified the BlackJack Lite game to assign cards that include both the card's type and number, add additional logic to ensure that the same card is not used twice in the same hand.
- Add scorekeeping logic to the BlackJack Lite game, and display the number of won and lost hands at the end of each game.