At the beginning of this chapter, I showed you the Petals Around the Rose game. This game uses all the skills you have learned so far, including the new concepts you learned in this chapter. If you haven't already done so, play the game now so you can see how it works, because it won't be as much fun once you know the secret.
Here's the basic plan of the Petals game: Each time the page is drawn, it randomly generates five dice, and calculates the correct number of petals based on a super-secret formula. The page includes a form that has a text area called guess for the user to guess the right answer. The form also includes a hidden field called numPetals, which tells the program what the correct answer was.
Can't the program simply remember the right answer?
Since the program generated the correct answer in the first place, you might be surprised to learn that the right answer must be hidden in the Web page and then retrieved by the same program that generated it. Each contact between the client and the server is completely new. When the user first plays the game, the page will be sent to the browser and then the connection will be completely severed until the user hits the Submit button. When the user submits the form, the petals program starts over again. It's possible the user plays the game right before he or she goes to bed, then leaves the page on the computer overnight. Meanwhile, a hundred other people might use your program. For now, you'll use hidden data to help keep track of the user's situation. Later in this book, you'll learn some other clever methods for keeping track of the users' situations.
The Petals game doesn't really introduce anything new, but it's a little longer than any of the other programs you've seen so far. I'll introduce the code in smaller chunks. Look on the CD-ROM for the program in its entirety.
Like most PHP programs, the Petals game uses some HTML to set everything up. The HTML is pretty basic because most of the interesting HTML will be created by the PHP code.
<HTML> <head> <title>Petals Around the Rose</title> </head> <body bgcolor = "tan"> <center> <font face = "Comic Sans MS"> <h1>Petals Around the Rose</h1>
I decided on a tan background with a whimsical font. This should give the program a light feel.
The main PHP code segment has three main jobs to do. These jobs are (appropriately enough) stored in three different functions. One goal of encapsulation is to make the main code body as clean as possible. This goal has been achieved in the Petals game.
<? printGreeting(); printDice(); printForm();
All the real work is passed off to the various functions, which will each be described shortly. Even before you see the functions themselves, you have a good idea what each function will do, and you also have a good sense of the overall flow of the program. If you encapsulate your code and name your functions well, it makes your code much easier to read and repair.
The purpose of this function is to print a greeting to the user. There are three possible greetings. If the user has never called this program before, the program should provide a welcome. If the user has been here before, he or she has guessed the number of petals. That guess might be correct (in which case a congratulatory message is appropriate) or incorrect, requiring information about what the correct answer was. The printGreeting() function uses a switch statement to handle the various options.
function printGreeting(){ global $guess, $numPetals; if (empty($guess)){ print "<h3>Welcome to Petals Around the Rose</h3>"; } else if ($guess == $numPetals){ print "<h3>You Got It!</h3>"; } else { print <<<HERE <h3>from last try: </h3> you guessed: $guess<br><br> -and the correct answer was: $numPetals petals around the rose<br> HERE; } // end if } // end printGreeting
This function refers to both the $guess and $numPetals variables, which are both automatically created. You can use one global statement to make more than one variable global by separating the variables with commas.
The $guess variable will be empty if this is the first time the user has come to the program. If $guess is empty, I print a welcoming greeting. If $guess is equal to $numPetals, the user has guessed correctly, so I print an appropriate congratulations. If neither of these conditions is true (which will be most of the time), the function will print out a slightly more complex string indicating the user's last guess and the correct answer. This should give the user enough information to finally solve the riddle.
The else if structure turned out to be the easiest option here for handling the three possible conditions I wanted to check.
After the program prints out a greeting, it does the important business of generating the random dice. It's relatively easy to generate random dice, as you saw from earlier in this chapter. However, I also wanted to be efficient and calculate the correct number of petals. To make the printDice() function more efficient, you'll see that it calls some other custom functions.
function printDice(){ global $numPetals; print "<h3>New Roll:</h3>"; $numPetals = 0; $die1 = rand(1,6); $die2 = rand(1,6); $die3 = rand(1,6); $die4 = rand(1,6); $die5 = rand(1,6); showDie($die1); showDie($die2); showDie($die3); showDie($die4); showDie($die5); print "<br>"; calcNumPetals($die1); calcNumPetals($die2); calcNumPetals($die3); calcNumPetals($die4); calcNumPetals($die5); } // end printDice
The printDice() function is very concerned with the $numPetals variable, but doesn't need access to $guess. It requests access to $numPetals from the main program. After printing out the "New Roll" message, it resets $numPetals to zero. The value of $numPetals will be recalculated each time the dice are rolled.
I got new dice values by calling the rand(1, 6) function six times. I stored each result in a different variable, named $die1 to $die6. To print out an appropriate graphic for each die, I called the showDie() function (which will be described next). I printed out a line break, then called the calcNumPetals() function (which will also be described soon) once for each die.
The showDie() function is used to simplify repetitive code. It accepts a die value as a parameter, and generates the appropriate HTML code for drawing a die with the corresponding number of dots.
function showDie($value){ print <<<HERE <img src = "die$value.jpg" height = 100 width = 100> HERE; } // end showDie
TRICK |
One advantage of using functions for repetitive HTML code is the ease with which you can modify large sections of code. For example, if you wish to change the image sizes, all you need to do is change the img tag in this one function, and all six die images will be changed. |
The printDice() function also calls calcNumPetals() once for each die. This function receives a die value as a parameter. It also references the $numPetals global variable. The function uses a switch statement to determine how much to add to $numPetals based on the current die's value.
Here's the trick. The center dot of the die is the rose. Any dots around the center dot are the petals. The value one has a rose but no petals. 2, 4, and 6 have petals, but no rose. 3 has two petals, and 5 has four. If the die roll is 3, $numPetals should be increased by 2, and if the roll is 5, $numPetals should be increased by 4.
function calcNumPetals($value){ global $numPetals; switch ($value) { case 3: $numPetals += 2; break; case 5: $numPetals += 4; break; } // end switch } // end calcNumPetals
The += code is a shorthand notation. The line
$numPetals += 2;
is exactly equivalent to
$numPetals = $numPetals + 2;
The first style is much shorter and easier to type, so it's the form most programmers prefer.
The purpose of the printForm() function is to print out the form at the bottom of the HTML page. This form is pretty straightforward except for the need to place the hidden field for $numPetals.
function printForm(){ global $numPetals; print <<<HERE <h3>How many petals around the rose?</h3> <form method = "post"> <input type = "text" name = "guess" value = "0"> <input type = "hidden" name = "numPetals" value = "$numPetals"> <br> <input type = "submit"> </form> <br> <a href = "petalHelp.html" target = "helpPage"> give me a hint</a> HERE; } // end printForm
This code places the form on the page. I could have done most of the form in plain HTML without needing PHP for anything but the hidden field, but when I start using PHP, I like to have much of my code in PHP. It helps me see the flow of things more clearly (print greeting, print dice, print form).