BACK TO THE HANGMAN GAME


Now it is time to return your attention to this chapter's game project, the Hangman game. The Hangman game is based on a children's game in which the player attempts to guess a secret word. If the player guesses the word before making six incorrect guesses, the player wins. Otherwise, he loses.

You will create the Hangman game by following the same five basic development steps that you followed when completing previous chapter projects.

Designing the Game

The Hangman game will be played within a single window. Therefore, it will be made up of one form and the 25 controls listed in Table 8.1.

Table 8.1: Form Controls for the Hangman Game

Control Type

Control Name

Description

Panel1

pnlLetters

Groups TextBox controls that will display letters of a guessed word

TextBox1

txtLetter1

Displays the first letter in the game's secret word

TextBox2

txtLetter2

Displays the second letter in the game's secret word

TextBox3

txtLetter3

Displays the third letter in the game's secret word

TextBox4

txtLetter4

Displays the fourth letter in the game's secret word

TextBox5

txtLetter5

Displays the fifth letter in the game's secret word

TextBox6

txtLetter6

Displays the sixth letter in the game's secret word

TextBox7

txtLetter7

Displays the seventh letter in the game's secret word

TextBox8

txtLetter8

Displays the eighth letter in the game's secret word

TextBox9

txtLetter9

Displays the ninth letter in the game's secret word

TextBox10

txtLetter10

Displays the tenth letter In the game's secret word

TextBox11

txtMisses

Displays the number of misses that the player has made

TextBox12

txtGuesses

Displays the letters that the player has already guessed (both right and wrong)

TextBox13

txtGamesWon

Displays the number of games that the player has won

TextBox14

txtGamesLost

Displays the number of games that the player has lost

GroupBox1

grpStats

Contains Label and TextBox controls that display game statistics

Label1

lblInput

Identifies the TextBox control where the player enters a letter guess

Label2

lblNoMissed

Identifies the TextBox control that displays the number of misses that the player has made

Label3

lblGuessed

Identifies the TextBox control that displays the letters that the player has already guessed (both right and wrong)

Label4

lblGamesWon

Identifies the TextBox control that displays the number of games that the player has won

Label5

lblGamesLost

Identifies the TextBox control that displays the number of games that the player has lost

Button1

btnSubmit

Executes code that checks to see if the player has guessed a letter in the secret word

PictureBox1

pbcHangmanBmp

Displays a graphic that shows how many letter guesses the player has missed

ImageList1

imlHangmanBmps

Stores an indexed collection of the Hangman images that are displayed in the PictureBox control

Step 1: Creating a New Visual C++ Project

The first step in creating the Hangman game is to open Visual C++ and create a new project, as outlined here:

  1. If you have not already done so, start Visual C++ 2005 Express and then click on File, New Project. The New Project dialog box will appear.

  2. Select Windows Application template.

  3. Type Hangman as the name of your new application in the Name field located at the bottom of the New Project window.

  4. Click on OK to close the New Project dialog box.

Visual C++ then creates a new project for you and displays a new form upon which you will design the game's user interface.

Step 2: Creating the User Interface

Now let's begin work on laying out the game's user interface by adding controls to the form and moving and resizing them in the appropriate locations. Refer to Figure 8.11 as you go through each step so that you know how to resize and place the controls.

  1. Begin by clicking on the form and setting its Size property to 655, 412.

  2. Add a Panel control to the form and resize it, as shown in Figure 8.11.

    Hint 

    A Panel control is a control that that stores and organizes other controls.

  3. Add 10 TextBox controls inside the Panel control and resize them.

  4. Add a Label control to the form. By default, Visual C++ names it Label1.

  5. Just to the right of the Labell control, add a TextBox control and a Button control.

  6. Add a GroupBox control at the bottom of the form and resize it until it takes up the bottom 30 percent of the form.

  7. Inside the GroupBox control, add four Label and four TextBox controls.

  8. Add a PictureBox control to the lower-right corner of the form and set its size to 200,200.

  9. Finally, add an ImageList control, which will appear in a Component Tray, located at the bottom of the Form Designer.

image from book
Figure 8.11: Examining the Layout of the Hangman game's user interface.

Now that you've completed the overall layout for the Hangman game user interface, you can begin form and control property customization.

Step 3: Customizing Form and Control Properties

Let's begin by modifying properties that are associated with the game's form, as shown in Table 8.2.

Table 8.2: Property Changes for Form1

Property

Value

Name

frmMain

Cursor

Hand

FormBorderStyle

Fixed3D

MaximizeBox

false

MinimizeBox

false

Size

540,360

StartPosition

CenterScreen

Text

Hangman

Next, modify the properties associated with the Panel control, as shown in Table 8.3.

Table 8.3: Property Changes for the Panel Control

Property

Value

Name

pnlLetters

BackColor

Menu

BorderStyle

Fixed3D

Then modify the properties associated with the GroupBox control, as shown in Table 8.4.

Table 8.4: Property Changes for the GroupBox Control

Property

Value

Name

grpStats

Text

Game Stats:

Now modify the properties associated with the TextBox controls, as shown in Table 8.5.

Table 8.5: Property Changes for the TextBox Controls

Control

Property

Value

TextBox1

Name

txtLetter1

BackColor

Menu

BorderStyle

None

Font.Size

36

Font.Bold

true

ForeColor

Menu Highlight

ReadOnly

true

TabStop

false

TextBox2

Name

txtLetter2

BackColor

Menu

BorderStyle

None

Font.Size

36

Font.Bold

true

ForeColor

Menu Highlight

ReadOnly

true

TabStop

false

TextBox3

Name

txtLetter3

BackColor

Menu

BorderStyle

None

Font.Size

36

Font.Bold

true

ForeColor

Menu Highlight

ReadOnly

true

TabStop

false

TextBox4

Name

txtLetter4

BackColor

Menu

BorderStyle

None

Font.Size

36

Font.Bold

true

ForeColor

Menu Highlight

ReadOnly

true

TabStop

false

TextBox5

Name

txtLetter5

BackColor

Menu

BorderStyle

None

Font.Size

36

Font.Bold

true

ForeColor

Menu Highlight

ReadOnly

true

TabStop

false

TextBox6

Name

txtLetter6

BackColor

Menu

BorderStyle

None

Font.Size

36

Font.Bold

true

ForeColor

Menu Highlight

ReadOnly

true

TabStop

false

TextBox7

Name

txtLetter7

BackColor

Menu

B Bold orderStyle

None

Font.Size

36

Font.

true

ForeColor

Menu Highlight

ReadOnly

true

TabStop

false

TextBox8

Name

txtLetter8

BackColor

Menu

BorderStyle

None

Font.Size

36

Font.Bold

true

ForeColor

Menu Highlight

ReadOnly

true

TabStop

false

TextBox9

Name

txtLetter9

BackColor

Menu

BorderStyle

None

Font.Size

36

Font.Bold

true

ForeColor

Menu Highlight

ReadOnly

true

TabStop

false

TextBox10

Name

txtLetter10

BackColor

Menu

BorderStyle

None

Font.Size

36

Font.Bold

true

ForeColor

Menu Highlight

ReadOnly

true

TabStop

false

TextBox11

Name

txtInput

CharacterCasing

Upper

Font.Size

18

Font.Bold

true

TextBox12

Name

txtMisses

ReadOnly

true

TabStop

false

TextBox13

Name

txtGuesses

ReadOnly

true

TabStop

false

TextBox14

Name

txtGamesWon

ReadOnly

true

TabStop

false

TextBox15

Name

txtGamesLost

ReadOnly

true

TabStop

false

Then modify the properties associated with the Button control, as shown in Table 8.6.

Table 8.6: Property Changes for the Button Control

Property

Value

Name

btnSubmit

Font.Bold

true

Text

Submit

Modify the properties associated with the Label controls, as shown in Table 8.7.

Table 8.7: Property Changes for the Label Controls

Control

Property

Value

Label1

Name

1blInput

 

Text

Enter A Letter Guess:

 

Font.Bold

true

Label2

Name

lblNoMissed

 

Text

No. Of Misses:

 

Font.Bold

true

Label3

Name

1blGuesses

 

Text

No. of Guesses:

 

Font.Bold

true

Label4

Name

1blGamesWon

 

Text

No. Games Won:

 

Font.Bold

true

Label5

Name

lblGamesLost

 

Text

No. Games Lost:

 

Font.Bold

true

From there, modify the properties associated with the PictureBox control, as shown in Table 8.8.

Table 8.8: Property Changes for the PictureBox Control

Property

Value

Name

pbcHangmanBmp

BorderStyle

Fixed3D

Size

200,200

SizeMode

StretchImage

Finally, change the Name property of the ImageList control to imlHangmanBmps and add the following bitmap images to the Images property (col1ection), as shown in Table 8.9. Don't worry about having to create these bitmap images yourself. I have included copies of them with the source for the game project on the book's companion Web site.

Table 8.9: Bitmap Images to Add to the ImageList Control's Images Collection

Property

File

Index No.

Name

100.bmp

0

Name

80.bmp

1

Name

60.bmp

2

Name

40.bmp

3

Name

20.bmp

4

Name

10.bmp

5

Name

0.bmp

6

Step 4: Adding a Little Programming Logic

Begin coding the Hangman game by double-clicking on the game's form, which causes Visual C++ to open the Code Editor and position the cursor on the game's Load event function, as shown here:

 private: System::Void frmMain_Load(System::Object^  sender,\ System::EventArgs^  e) { } 

Above the Load function, add the code to the area reserved for module variables, as shown next:

 private:      /// <summary>      /// Required designer variable.      /// </summary>      //Array to hold game words      array<String^>^ strWordListArray;      //String for game's current word      String^ strGameWord;      //String for missed guesses      String^ strWrong;      //Counter for missed guesses      Int32 intMisses;      //Counter for correct guesses      Int32 intNoRight;      //Counter for games won      Int32 intGamesWon;      //Counter for games lost        Int32 intGamesLost:      //Controls display of Hangman image      Int32 intHangmanNo; 

These statements define a special type of .NET array capable of handling arrays of strings, two variables (handles) for holding the game's current word and missed guesses, and several Int32 counters that track the player's progress. The final variable, intHangmanNo, controls which image of the gallows to display, based on the player's progress in the game.

Now add the following statements to the Form1_Load function:

 private: System::Void frmMain_Load(System::Object^  sender,\ System::EventArgs^  e) {      strGameWord = gcnew String("");      strWrong = gcnew String("");      intGamesWon = 0;      intGamesLost = 0;      intHangmanNo = 6;      //Populate the array with words       LoadWordArray();      //Set up the game's starting values      InitializeGameStats();      StartTheGame();  //Start the game } 

The function begins by setting aside memory for two of the game's String handles—strGameWord and strWrong—and initializing both to an empty value (for example, using ""). Next, the number of games won and lost is set, as is the variable, intHangmanNo, that will later control what gallows image to display. Finally, the Form1_Load function sets up gameplay by calling three custom functions. The LoadWordArray function populates the strWordListArray array with 20 secret words. To create it, scroll down below the Form1_Load function and enter the following statements:

 private: Void LoadWordArray( Void ) {     const Int32 cintArraySize = 20;     StrWordListArray = \       gcnew array<String^>(cintArraySize);     strWordListArray->SetValue( "ELEPHANT", 0 );     strWordListArray->SetValue( "CARRIAGE", 1 );     strWordListArray->SetValue( "ENVELOPE", 2 );     strWordListArray->SetValue( "PRESIDENT", 3 );     strWordListArray->SetValue( "ELLIPTICAL", 4 );     strWordListArray->SetValue( "MARKER", 5 );     strWordListArray->SetValue( "BATTLESHIP", 6 );     strWordListArray->SetValue( "TERMINATE", 7 );     strWordListArray->SetValue( "REJOICE", 8 );     strWordListArray->SetValue( "LIBERTY", 9 );     strWordListArray->SetValue( "CLASSIC", 10 );     strWordListArray->SetValue( "REFLEX", 11 );     strWordListArray->SetValue( "VERSION", 12 );     strWordListArray->SetValue( "DWELLING", 13 );     strWordListArray->SetValue( "APARTMENT", 14 );     strWordListArray->SetValue( "MATRIX", 15 );     strWordListArray->SetValue( "FAUCET", 16 );     strWordListArray->SetValue( "BEDROOM", 17 );     strWordListArray->SetValue( "VOLLEY", 18 );     strWordListArray->SetValue( "WHISTLE", 19 ); } 

This function first uses gcnew to initialize an object to hold all the strings. The format is a bit tricky to understand at first, but what the function does is to first declare a constant, cintArraySize, that is set to the value 20. This constant then sets the size of the array requested (20 elements). The gcnew keyword allocates an array (using the array keyword) of String handles, which are denoted by the syntax String^. The resulting block of memory is then populated with all the words within the game using the SetValue method for each element.

Next, the InitializeGameStats function sets the game statistics displayed in the GroupBox control to zeroes. You'll need to create this function from scratch by inserting it just under the LoadWordArray function. Its format is as follows:

 private: Void InitializeGameStats( Void ) {     //Reset and display games won and lost     intGamesWon = 0;     intGamesLost = 0;     txtGamesWon->Text = intGamesWon.ToString();     txtGamesLost->Text = intGamesLost.ToString(); } 

The StartTheGame function is responsible for setting up the game to play a new round. It does so by making three function calls, which reset variable defaults, retrieve a secret game word, and format the word for display. The function ends by setting focus to the txtInput control to ready the game for the player input:

 private: Void StartTheGame( Void ) {     //Reset game settings     ResetDefaultSettings();     //Get a word for the player to guess     RetrieveWord();     //Format the display of the mystery word     FormatGameWord();     //Prepare to accept the player's guess     txtInput->Focus(); } 

Next, create the ResetDefaultSettings function, shown next, to prepare the game to play a new round:

 private: Void ResetDefaultSettings( Void ) {     //Reset all game settings     intMisses = 0;     intNoRight = 0;     txtGuesses->Text = "";     txtMisses->Text = intMisses.ToString();     txtInput->Text = "";     intHangmanNo = 6;     pbcHangmanBmp->Image =\     imlHangmanBmps->Images->default[intHangmanNo]; } 

Note that in addition to resetting variable default values, the final statement in the previous function displays an empty hangman's gallows graphic in the PictureBox control.

Now create the RetrieveWord function. The function first creates a random number generating object, randNumGen, from the Random object and seeds it with the current time (expressed as DateTime::Now). Then you choose a random number based on a range specified by strWordListArray->Length, which is the length of the array. You use this value to access the array using strWordListArray->GetValue(intRandomNo)->ToString(). Note that this last statement looks more complicated than it actually is. It gets the value of the location specified by intRandomNo using the array object's GetValue method and then converts that value to a String data type. This allows the value to be assigned to strGameWord, thus creating the secret word:

 private: Void RetrieveWord( Void ) {     //Seed random number generator with current time     DateTime moment = DateTime::Now;     Random^ randNumGen = gcnew Random( moment.Millisecond );      //Declare a variable to hold a randomly     //  generated number     Int32 intRandomNo = 0;     //Use the Random object's Next method to retrieve     //  a number between zero and the number     //  of words in the array     intRandomNo = randNumGen->Next( strWordListArray->Length );     //Use the random number to select a word from     // the array     strGameWord = \       strWordListArray->GetValue(intRandomNo)->ToString(); } 

Next, create the FormatGameWord function, as shown next. The function begins by assigning an empty string to each of the 10 TextBox controls that display the letters making up the game's secret word. The function then sets up a for loop to display an underscore character for each letter in the secret word:

 private: Void FormatGameWord( Void ) {     //Game words are limited to 10 or fewer characters.     //  Each letter is stored in a separate TextBox     //  control. Start formatting by setting the value     //  stored in each TextBox control to a blank character     txtLetter1->Text = "";     txtLetter2->Text = "";     txtLetter3->Text = "";     txtLetter4->Text = "";     txtLetter5->Text = "";     txtLetter6->Text = "";     txtLetter7->Text = "";     txtLetter8->Text = "";     txtLetter9->Text = "";     txtLetter10->Text = "";     //Loop once for each word in the current letter and     //  set an underscore in the appropriate text box     for( Int32 intCounter = 0; intCounter <= strGameWord->Length;          intCounter++ )     {       if( intCounter == 1 )         txtLetter1>Text = "_";       if( intCounter == 2 )         txtLetter2->Text = "_";       if( intCounter == 3 )         txtLetter3->Text = "_";       if( intCounter == 4 )         txtLetter4->Text = "_";       if( intCounter == 5 )         txtLetter5->Text = "_";       if( intCounter == 6 )         txtLetter6->Text = "_";       if( intCounter == 7 )         txtLetter7->Text = "_";       if( intCounter == 8 )         txtLetter8->Text = "_";       if( intCounter == 9 )         txtLetter9->Text = "_";       if( intCounter == 10 )         txtLetter10->Text = "_";      } } 

You can create the next function, shown below, by returning to the Form Designer, double-clicking on the btnSubmit control, and then modifying the function:

 private: System::Void btnSubmit_Click(System::Object^  \ sender, System::EventArgs^  e) {     //Make sure input is valid     if( !PlayerInputValid() )       return;  //Exit on invalid guess     //If the letter has already been guessed, display an error     if( txtGuesses->Text->Contains( txtInput->Text->ToUpper() ) )       MessageBox::Show("Error:"       "That letter has already been guessed.");     else //Check whether a correct letter was guessed     {       //Add the letter to the list of already guessed letters       txtGuesses->Text = String::Concat( txtGuesses->Text,                            txtInput->Text );       //Look for the letter in the word       if( !strGameWord->Contains( txtInput->Text->ToUpper() ) )       {         //The player's guess was wrong         //Append letter to the list of missed guesses         strWrong = String::Concat( strWrong,                     " ", txtInput->Text->ToUpper() );         //Update and display missed guesses         intMisses += 1;         txtMisses->Text = intMisses.ToString();         //Reduce the counter used to control the Hangman picture and         // update graphic         intHangmanNo -= 1;        pbcHangmanBmp->Image =\          imlHangmanBmps->Images->default[intHangmanNo];        //End game at six wrong guesses        if( intMisses == 6 )        {          //Update lost games and inform player          intGamesLost += 1;          txtGamesLost->Text = intGamesLost.ToString();          //Call procedure to see if player wants to play again          MessageBox::Show( "Sorry. You have lost." );          PromptForNewGame();          return;        }      }      //Use for loop to check each letter in the word      for( Int32 intCounter = 0; intCounter <= \          strGameWord->Length; intCounter++ )      {        //Select one letter at a time        if( String::Compare( strGameWord, intCounter,            txtInput->Text, 0, true ) == 0 )        {          //Update and display guesses          intNoRight += 1;          FlipGameLetter( intCounter );        }      }     }     //See if the player has guessed every letter in the word     if( intNoRight == strGameWord->Length )     {       intGamesWon += 1;       txtGamesWon->Text = intGamesWon.ToString();       //Call the procedure to see if the player wants to play again       MessageBox::Show( "Congratulations. You have Won!" );       PromptForNewGame();     }     txtInput->Text = "";     txtinput->Focus(); } 

The function begins by making sure that the player input is correct by calling the PlayerInputValid function. If the input is okay, the function continues to execute.

Next, the function uses an if...else statement to see if the player has entered a letter guess that has already been tried. This is done by converting input to uppercase and then searching the string for an instance of the letter. Specifically, the txtInput->Text property is converted to uppercase using the ToUpper method. Then it is supplied as an argument to the txtGuesses->Text object's Contains method. (Incidentally, this method is available to all String objects.)

If the player guesses a new letter, that letter is appended to the end of the string displayed in the txtGuesses control. This is done, as in previous chapters, using the highly useful String::Concat method, which can join several strings.

Next, an embedded if statement checks whether the player's guess is wrong by using the object's Contains method. If the player guesses incorrectly, the StrWrong string containing incorrect guesses is updated. Then the value holding the number of misses is updated and stored in the txtMisses control, and the graphic displayed in the PictureBox control is changed to reflect the number of misses so far. A check is then made to see if the player has missed the maximum of six guesses and lost the game.

If the player has not lost, a for loop iterates through the secret word comparing each of its letters with the letter the player entered. For each correct letter, the game updates the counter, keeping track of the number of right answers. It also displays the corresponding letter using the FlipGameLetter function.

Finally, a check is made to see if the player has guessed all the letters that make up the secret word, thus winning the game. If the player has not won the game, the txtInput control is cleared and given focus, thus preparing the game for the player's next guess.

Next, you need to manually create the PlayerInputValid function. This function needs to return a value, so you must define it as shown here:

 private: Boolean PlayerInputValid( Void ) {     //Create a list of letters to compare input to     String^ strAlphabet = gcnew String( \     "ABCDEFGHIJKLMNOPORSTUVWXYZ" );     //See if the player clicked on Submit without     //  entering a guess     if( txtInput->Text == "" )     {       MessageBox::Show("Error: You must enter a letter.");       txtInput->Text = "";       txtInput->Focus();       return false;     }     //See if the player entered more than one character     if( txtInput->Text->Length > 1 )     {       MessageBox::Show("Error: Please enter only 1 letter." );       txtInput->Text = "";       txtInput->Focus();       return false;     }     //See if the player entered a number     if( !strAlphabet->Contains( txtInput->Text ) )     {       MessageBox::Show("Error: Please enter a letter.");       txtInput->Text = "";       txtInput->Focus();       return false;     }     return true; } 

The function performs three input validation tests to make sure the player has provided an acceptable guess. It accomplishes this using three if statements. The first if statement makes sure that the player has entered something. The second if statement makes sure that the player has not entered more than one character, and the third if statement makes sure that the player hasn't entered a number.

Each time the player correctly guesses a letter, the FlipGameLetter function executes. You need to manually create this function, as shown here:

 private: Void FlipGameLetter( Int32 intLetterNumber ) {      //Match the letter to be displayed with the      //  correct text box and show the letter      switch( intLetterNumber )      {        case 0 :          txtLetter1>Text = txtInput->Text->ToUpper();          break;        case 1 :          txtLetter2->Text = txtInput->Text->ToUpper();          break;        case 2 :          txtLetter3->Text = txtInput->Text->ToUpper();          break;        case 3 :          txtLetter4->Text = txtInput->Text->ToUpper();          break;        case 4 :          txtLetter5->Text = txtInput->Text->ToUpper();          break;        case 5 :          txtLetter6->Text = txtInput->Text->ToUpper();          break;        case 6 :          txtLetter7->Text = txtInput->Text->ToUpper();          break;        case 7 :          txtLetter8->Text = txtInput->Text->ToUpper();          break;        case 8 :          txtLetter9->Text = txtinput->Text->ToUpper();          break;        case 9 :          txtLetterl0->Text = txtInput->Text->ToUpper();          break;      } } 

This function consists of a single switch statement, which compares the player's guess to each letter in the secret word and flips (that is, displays) any letters that match the guess.

The last function that you need to create is the PromptForNewGame function. You must manually define this function and then set it up as shown here:

 private: Void PromptForNewGame( Void ) {     //Variable used to hold player response     Windows::Forms::DialogResult drPlayAgain;     //Prompt player to try again     drPlayAgain = MessageBox::Show(     "Would you like to play again?", "Hangman",     MessageBoxButtons::YesNo, MessageBoxIcon::Question,     MessageBoxDefaultButton::Button1 );     //if player clicks on Yes, set up a new game     if( drPlayAgain == Windows::Forms::DialogResult::Yes )       StartTheGame(); //Start a new game     else // End the game       this->Close(); } 

The function uses the MesssageBox::Show method to ask if the player would like to play another round. If the player clicks on the Yes button, the StartTheGame function executes. Otherwise, the Close method, accessed through your form application's this keyword, terminates the application.

Step 5: Testing the Execution of the Hangman Game

The Hangman game is now complete. Press F5 and test the game to make sure everything is working properly. If you run into errors, check to see if you have made one or more typing mistakes. If you decide to share the game with others, remember to test all aspects of the game, including feeding it good and bad input.




Microsoft Visual C++ 2005 Express Edition Programming for the Absolute Beginner 2006
Microsoft Visual C++ 2005 Express Edition Programming for the Absolute Beginner 2006
ISBN: 735615381
EAN: N/A
Year: 2005
Pages: 131

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