This is the solution to the challenge titled ChallengeMegaCasino. Because this is a relatively large project, the best way to approach it is in pieces by breaking the task up into smaller tasks, then completing those. This solution will detail that process, and the process of making the pieces work together.
The first step is to create the Default.aspx page that the user will be interacting with. Create a project called MegaChallengeCasino, then add a new Default.aspx page as we've done this far in the series. Per the instructions, we'll need images, labels, a TextBox and a Button on our page:
The programmatic IDs for the Server Controls are as follows:
Note: Make sure the three Image Server Controls are sized to 150px x 150px.
Next, add a new folder to your project and call it Images:
Drag and drop the images provided in CS-ASP_034-Mega-Challenge_Code into this folder so we can later programmatically reference them.
The first task to complete is to create a method to display a random image in each of the three Image Server Controls. To begin, double-click the pullButton to generate a pullButton_Click EventHandler. Often times, a helpful way to start is by creating an outline for your code written in comments. These comments will dictate in general language what your program will do and lays out a plan for you to follow:
To accomplish this task, we'll add the names of each of the images in the Images folder to an array of strings. When retrieving a random image for the server control, we will access a random item in that array (Such as "Clover") that we append .png to in order to reference it for the ImageUrl property.
While this task will ultimately be accomplished by a helper method, we will first write the logic inside the pullButton_Click, test the functionality, and then create the method. To begin, create an array of string called images and populate it with the names of the images in the Images folder:
Next, we'll create a new Random class called random, and create a string called image that is set to a random index from the images array:
Finally, set the Image1.ImageUrl to the following string concatenation that references an image in the Images folder:
The code we've written creates the functionality needed for retrieving a random image, but clutters up the pullButton_Click in the process. What we can do is pull most of the code out and create a helper method to do this task. Create a new private string method called spinReel(), then copy and paste this code from the pullButton_Click:
Notice that we're getting an error from the spinReel() method, though. This is because we're expected to return a string from the method. To accomplish this, instead of setting a string equal to the random index of images, we'll return that random index:
Now notice that the error warning is gone, and the method is satisfied. We'll call the method back in the pullButton_Click, setting it equal to a string called image. Save and run the code to see the results:
While spinReel() successfully performs the function necessary to get a random image, it only does it for one image. Since we need three different values, we'll need to call spinReel() three times, then save those values to be assigned to our images. Our goal is to have as little clutter as possible in the pullButton_Click, so we'll delegate this responsibility to yet another helper method called pullLever().
This will be a void method, it won't return a value. Inside of its code block, we'll create a new string array called reels that will hold the three different values from spinreel():
This will work because spinReel() will return a string, and the array is of type string, so we are simply populating it with three different string values.
Now that we've retrieved the values, we need to display them on-screen. We'll do this by creating another helper method called displayImages(). We'll have an input parameter of string reels so that we can access the indexes in that array. Then, copy and paste the Image1.ImageUrl code into the method. Duplicate it for each image, then set the three ImageUrl's to the following:
Call displayImages() in the pullLever() method, passing in the reel array. Finally, call pullLever() from the pullButton_Click. Save the application and run to see the result:
Notice that every time you press the button, you'll end up with the same three images. The reason for this has to do with the Random class. There's a .txt file in the CS-ASP-034-Mega-Challenge_Code folder that explains in-depth why this happens. In summary, every time you create an instance of the Random class, it is created using the DateTime stamp, down to the millisecond. The result is that, in our case, when we create three different instances of Random and call random.Next(), the next index is always the same as the last. Why? Because we are not actually going to the next index, but simply calling the next index on another instance of the class, which will be the same index as the previous instance.
Thankfully, the solution to this issue isn't very difficult: Copy and paste the line of code that creates the instance of Random to the top of the Default.aspx.cs file so that the same instance is accessible throughout all of the method calls:
Now, save and run your project to see the result:
The next thing step that we need to take is finding what the multiplier for the player's bet is based upon what reel images are present. The multiplier can be summarized as follows:
The code logic we'll write to incorporate this will be in a method that will be called from the pullLever() method. However, this will require pullLever() to know what amount was bet, and return an integer for the winnings. We'll modify the method to look like this:
Notice that IntelliSense is great for telling us that we're expected to return an integer value from this method, denoted by the red squiggly line. But now we also need to create a bet integer to pass in to the method.
In the pullButton_Click, we'll initialize an int bet that's equal to 0. Then, directly underneath, we'll setup a conditional to ensure that the value passed in to the betTextBox can be converted to an int and, if so, set bet equal to that value. To do that, we'll use int.TryParse(), passing in the TextBox and the bet variable. Then we'll modify the pullLever() call, passing in the bet variable:
Returning to the pullLever() method, we'll now create the multiplier variable, setting it equal to an evaluateSpin() method which we've yet to create:
The evaluateSpin() method needs the reel variable as an input so that it knows what the result of the spin was. Since we're referencing a method that we'll need to create, press Ctrl+. on your keyboard and generate a method stub from it. This will create a method template for evaluateSpin(), including the int return expectancy and reel input:
The first step we'll take in determining the multiplier is to set up different methods for each scenario. If there are any BARs, we will immediately return out of the method with a value of 0 for the multiplier. If it's a jackpot, we'll return with 100. If there's Cherries, we'll return either 2, 3 or 4. Since there is a limit on the number of lines of code per method, we'll need to create a new method for each evaluation, passing in the reel array for each:
Here's how this works: we create a boolean type method for the first two checks that, if true, return their values. The check for cherries is more difficult, however, because there are multiple possible return values. Because of this, we'll need an output parameter for the multiplier, and then we'll return that multiplier to the caller. If none of these evaluate true, we'll return 0 to the caller, and the bet amount will be lost.
We now need to flesh out each of the three method calls that we made, generating a stub for each. Start with isBar() by pressing Ctrl+. while your cursor is on the line, then generating the method stub. Inside of that method stub, we'll create a conditional check to see if any of the reels are a BAR, and if so we'll return true. Otherwise, we'll return false, since there is no BAR:
Next, generate a method stub for the isJackpot() method. Inside of that code block, we'll create a conditional statement for the antithesis of isBar(), checking instead if all reels are equal to "Seven":
The last condition we need to check is if there are cherries in the reel spin. Create a new private int method called determineCherryCount(), passing in reel. Inside its code block, write the following code:
This code block evaluates how many reels contain the string "Cherry" and sets the cherryCount variable accordingly.
Next, create another method that returns an int and call it determineMultiplier(), passing in yet again the reel. Inside, write the following code to set the multiplier based on the cherryCount:
This will take evaluate cherryCount, as passed in by determineCherryCount(), and return the appropriate value back to the caller, whether 0, 2, 3 or 4. Go back to the isWinner() method, and set the multiplier variable equal to determineMultiplier(), passing in reel. Underneath that, create a conditional statement to check if the multiplier is greater than 0. If it is, isWinner() will return true. Otherwise, it will return false:
Finally, return back to the evaluateSpin() method and tidy it up so it looks like the following, keeping within the six-line limitation:
Now that we've determined the multiplier, as well as the bet, we can calculate the player's total earnings. Return to the pullLever() method, and underneath the call to evaluateSpin(), write the following code:
This will satisfy the method's return, and give us the total amount that the player either won or lost. We'll use this value to display back to the user in the resultLabel.
Return to the pullButton_Click. What we need to do is use the bet returned from pullLever() and assign it to an integer variable called winnings. Then, call a new method named displayResult(), passing in the bet and winnings variables:
Use that call to displayResult() to create a method stub. Inside that method, we'll need to display one of two messages: either tell the user they won, and how much, or tell them they lost the value they bet. To do that, create an if statement to check if the winnings are greater than 0, and inside, write the following code to set the resultLabel:
Underneath, write an else statement to display the other message. Note the use of ':C' within the brackets for currency formatting:
Now, save and run your application to see the result:
One of the requirements of this challenge is to display, at runtime, the player's current money, and show three reel values before the player pulls the lever. To do this, we'll need to go into the Page_Load event, and write a conditional statement to ensure that the page is not posting back. Inside, we'll create another string array called reels, and set it equal to spinReel():
Next, call the displayImages() method, passing in the array of reels we just created. Running the program will show the initial state of the application:
What we need to do now is initialize the player's money value, which is given to us as $100. Since we know that the value of the player's money will need to be saved between posts to the server, we'll initialize the value using the ViewState. Within the same conditional code block for !Page.IsPostBack(), write the following code for the value and key:
When the application first loads, the player needs to be able to see their initial money value. This means that a helper method is needed in order to display the money value to the user. Create a method called displayPlayersMoney(), and inside set the moneyLabel's text to the following:
This method accesses the current money value of the player from ViewState and displays it in the challenge's specified format. This functionality is reusable for when we update the player's total money.
In order to update the amount of money available to the player, create a new method within pullButton_Click called adjustPlayersMoney(), passing in the bet and the winnings and generate a method stub for it:
Inside the code block, create an integer called playersMoney, setting it equal to the ViewState's PlayersMoney value. Since this will return an object, it needs to be cast to an integer:
Now that we've retrieved the player's money prior to the bet, we can calculate how much money the player has after they've played the game. To do this, we'll subtract the bet from the playersMoney variable, add the winnings and update the ViewState:
Now, in the pullButton_Click, call the displayPlayersMoney() method underneath the call to adjustPlayersMoney. Save and run the application to see the result.
This completes the solution to MegaChallengeCasino. The purpose of this challenge was to test your knowledge of creating helper methods and delegating tasks to several methods in order to keep the separation of concerns principle in place. It comes down to a lot of thought and planning, but once you have a plan in place, the execution can prove to be more straightforward than it appears at first.
Hopefully you were able to solve most, if not all, of this challenge on your own. Again, if you met the requirements for the challenge but had a different implementation, that's fine! There are many different ways to solve this challenge, and you're encouraged to try several different methods. The more you test and practice, the more you'll learn and you'll become better at programming. Keep up the good work!
Solution - Mega Challenge Casino