In this chapter we will develop a Hangman game.
To start off this
chapter, we are going to learn about the ++ and the -- operator.
They are unique operators that can come in very handy. If ++ is
written after a variable then the variable becomes 1 more than
it's previous value. If -- is written after a variable the
variable becomes 1 less than it's previous value. The operators
can also come before the variable, but that changes what they do.
Consider the following code:
int
Var = 3;
Var--;
Var will
equal 2 after the second statement. The developers of C++,
Bell Labs, were fans of fancy code. Look at the following
code:
int
Count = 0;
while(Count
< StringSize)
{
Array[Count++] = Count;
}
The above code in the
loop is equivalent to the following:
Array[Count] = Count;
Count = Count + 1;
The ++ and -- operator when preceding the variable has the highest precedence in the order of operations. The ++ and -- operator following the variable has the lowest precedence in the order of operations and is executed after all other operations including the assignment operation!
Type
casting is a way to change the type of a variable.
Consider the following code:
char
Answer[20] = "34";
int
Number = 34;
if
(Number == Answer)
{
}
The
above code will produce a compiler error because they are of
different types. To get around this we type cast. To
type cast write the type you want to change a variable to in
parenthesis and in front of the variables name like this:
if(Number
== (int) Answer)
Now
let's go over the for loop. The for loop is a very
readable loop that has the following syntax:
for(code;
condition; code)
{
}
The
initial code is executed first and then the condition is
checked. If the condition is true the code within the
braces is executed. Finally the part of the code that is
written after the condition is executed. Then the condition
is reevaluated. After that it will execute the code within
the braces again and then check the condition. Here is an
example:
for(int
Count = 0; Count < 5; Count++)
{
cout<<Count<<endl;
}
output:
0
1
2
3
4
Access to variables and constants can be confusing in C++ to beginner programmers. Their are three access types dynamic, global and auto.
Type | Definition | Examples |
auto | Auto access variables and constants are created and accessible on declaration and are destroyed after the closing brace for the pair of braces that it was created in. They are only accessible inside of the function they were declared unless they are passed to another function. | void
main() { int Var; } |
dynamic | Dynamic variables and constants are created when a person uses the new operator. They are destroyed when the program exits or when the user uses the delete operation on it. Dynamic structures are accessible through pointers. | Pointer
= new int; delete Pointer; |
global | Global variables are accessible anywhere in the program and exists from declaration and are destroyed when the program exits. Any variable or constant in a header file or that is outside of braces is global. | #define MAX
3 int Variable void main() { } |
We
won't use pointers or dynamic variables until a later chapter so
don't worry about them.
In C++
you can create your own types using typedef. Here is
the syntax:
typedef
type type Name;
Name
Variable;
Here is
an example:
typedef
char String[15];
String
Words[23];
The above makes an array of arrays. In games this allows us to place strings in arrays as we will do in Hangman.
File use
in C++ is our next topic. We will use fstream.h to access
files. We can use two file streams in and out. We
need to declare a variable to access them. For a stream
that takes input from a file we need type ifstream and ofstream
for file output. These streams are classes. We
will learn how to use classes in the next chapter. Classes
can have special functions accessible using the class name
followed by a period and the function name. For file
streams we use the open, close and peek functions. open
takes a file name and opens the file. close closes a
file. peek returns the next character. All ascii
files end with a character known as the EOF or end of
file character. peek is usually used in a while
condition to exit when EOF is found. With input files we
can use the right bit shift operator and with output files we can
use the left bit shift operator. Consider we have a file
Numbers.dat that has the following:
123
35 234 88
980
65
We could
use the following code to output the above numbers to the screen:
ifstream
DatFile;
DatFile.open(Numbers.dat)
int
Number;
while((C=Datfile.peek())
!= EOF)
{
DatFile>>Number;
cout<<Number<<endl;
}
DatFile.close();
output:
123
35
234
88
980
65
DON'T
FORGET TO CLOSE THE FILE! Having files open uses a large
amount of system resources and if you don't close it the file
will be inaccessible till the program ends.
Escape
sequences are used in strings to add special characters to a
string. \0 is an escape sequence for the null string and \n
for a new line character. To write the '\' character you
must type '\\' .
Now here is Hangman:
// main4a.cpp
//
This is the source to hangman by Forest J. Handford
//
Copyright (c) 1998
//////////////////////////////////////////////////////
#include
<iostream.h> // For input/output
#include
<fstream.h> // For file input/output
#include
<string.h> // For strcpy
#include
<time.h> // For time
#include
<stdlib.h> // For toupper and tolower
#define
MAX_WORD_SIZE 15 // The max size for words
#define
MAX_WORDS 255 // The max number of words
void
LoadFile(); // Prototypes for our functions
void
RunGame();
void
DrawGallows(int State);
typedef
char String[MAX_WORD_SIZE]; // Make a char type with 15 chars
String
Words[MAX_WORDS - 1]; // This array will hold our words
int
Count; //word count
//
the main function of our hangman game
void
main()
{
char
Continue = 'Y'; // end game if = to 'N'
cout<<"Welcome
to Hangman . . . Don't lose your head!"<<endl;
LoadFile(); // Load the data file
//
Continue the game as long as the player wants
while(Continue
== 'Y')
{
RunGame(); // Run the game
cout<<endl<<"Do you want to play again (Yes or
No)? ";
cin>>Continue;
Continue = toupper(Continue);
}
//
say good bye
cout<<endl<<"Thanks
for playing."<<endl;
}
//
This will load our file
void
LoadFile()
{
char
C; //Used to find EOF
ifstream
Datfile; //The in file
Count=0;
//Set count to 0
//
Open the data file
Datfile.open("words.dat");
//Loop
till the end of file
while((C=Datfile.peek())
!= EOF)
{
// Get the next word and then increment Count
Datfile>>Words[Count++];
// If we surpass the max exit and tell the user
if(Count > MAX_WORDS - 1)
{
cout<<endl<<"Too many words in the file,
stopping with "
<<MAX_WORDS<<" Words."<<endl;
Count = MAX_WORDS;
break;
}
}
//
We need to subtract one to get the correct number of words
Count--;
//
Close the data file
Datfile.close();
}
//
This function will run the game
void
RunGame()
{
int
Word; // This will hold the subscript of our word
int
Size; // This will hold the length of our word
int
State=1; // This holds the game state
int
Subscript=0; // This will hold subscripts
char
Guess[MAX_WORD_SIZE]; // this will hold their current word
char
Copy[MAX_WORD_SIZE]; // This will hold a copy of the word
char
Letter; //This will be their letter guess
int
Correct=0; // This is a True/False value deciding if they
got a good answer
//
Seed and create a random number
srand((unsigned)time(
NULL )); // use time as a seed
Word
= rand() % Count;
//
Make a local copy of the word
strcpy(Copy,Words[Word]);
Size = strlen(Words[Word]); // Get the word's size
//
Create a null terminated string to represent the word as the
//
player knows it.
for(;
Subscript < Size; Subscript++)
{
Guess[Subscript] = '-';
}
//
insert the null character
Guess[Subscript]
= '\0';
//
Go till the player is hung
while(State!=6)
{
DrawGallows(State); //Draw the gallows
cout<<Guess<<endl; // Draw Guess
cout<<"Guess a letter :";
cin>>Letter;
// We will use only lower case letters
Letter = tolower(Letter);
// Loop through the word
for(Subscript = 0; Subscript < Size; Subscript++)
{
//if the guess is good tell the user and update Guess
if(Copy[Subscript] == Letter)
{
Guess[Subscript] = Letter;
Correct = 1;
cout<<endl<<"Good Guess!";
// If guess equals the word they won so exit
if(strcmp(Words[Word],Guess) == 0)
{
cout<<endl<<"Yea, You survived and won!";
return;
}
}
}
// If they didn't get aletter correct chide the user
if(Correct == 0)
{
cout<<endl<<"Sorry, bad guess!";
State++;
}
Correct = 0; // reset Correct
}
DrawGallows(State);
//Draw the gallows at end of game
//They
lost if they are here so tell them the answer.
cout<<"The
word was : "<<Words[Word]<<endl<<endl;
}
// This will Draw
the gallows according to the state
void DrawGallows(int State)
{
if(State==6)
{
// The \\ will translate as '\' because it is a
special char
cout<<endl<<endl
<<"
+----+ "<<endl
<<" |
| "<<endl
<<" |
O "<<endl
<<" |
/|\\ "<<endl
<<" | /
\\ "<<endl
<<" |Your Dead
"<<endl
<<"
============"<<endl<<endl;
}
else if(State==5)
{
cout<<endl<<endl
<<" +----+
"<<endl
<<" |
| "<<endl
<<" |
O "<<endl
<<" | /|\\
"<<endl
<<"
| \\ "<<endl
<<"
| "<<endl
<<"
============"<<endl<<endl;
}
else if(State==4)
{
cout<<endl<<endl
<<" +----+
"<<endl
<<" |
| "<<endl
<<" |
O "<<endl
<<" | /|\\
"<<endl
<<"
| "<<endl
<<"
| "<<endl
<<"
============="<<endl<<endl;
}
else if(State==3)
{
cout<<endl<<endl
<<" +----+
"<<endl
<<" |
| "<<endl
<<" |
O "<<endl
<<" |
/| "<<endl
<<"
| "<<endl
<<"
| "<<endl
<<"
============="<<endl<<endl;
}
else if(State==2)
{
cout<<endl<<endl
<<" +----+
"<<endl
<<" |
| "<<endl
<<" |
O "<<endl
<<" |
| "<<endl
<<"
| "<<endl
<<"
| "<<endl
<<"
============="<<endl<<endl;
}
else if(State==1)
{
cout<<endl<<endl
<<" +----+
"<<endl
<<" |
| "<<endl
<<"
| "<<endl
<<"
| "<<endl
<<"
| "<<endl
<<"
| "<<endl
<<"
============="<<endl<<endl;
}
}
Header files can be used
to define functions. Everything declared in headers and all
the include files can be used in any file they are included
in. To include a header that is in the same directory as
the cpp file use " marks instead of <> . If we
had a file called my.h that had:
#include <iostream.h>
int Size = 4;
void Hello()
{
cout<<"Hello"<<endl;
}
and had the following in
a cpp file:
#include "my.h"
void main()
{
cout<<Size<<endl;
Hello();
}
the output would be:
4
Hello
To use the output stream we need to declare the file with the ofstream type. We can output to the file using the << operator. When we output to a file we must separate the output so that we can retrieve it easily. The /t escape sequence adds a tab to output and /n to adds a new line.
I think we are ready for a utility to add remove words from a word file. The ofstream's and ifstream's open functions will create a file even if the file doesn't exist. In the hangman game I didn't allow for file errors. If you wanted to close the program you could check to see if the count was equal to 0 after loading the words. Here is our hangman file utility:
< Header > < Main > < Program >
//
loadfile.h
// This is the header file to include to load files for
// hangman
// Copyright (c) 1998 Forest J. Handford
///////////////////////////////////////////////////////
#include
<iostream.h> // For input/output
#include <fstream.h> // For file input/output
#define
MAX_WORD_SIZE 15 // The max size for words
#define MAX_WORDS 255 // The max number of words
typedef char
String[MAX_WORD_SIZE]; // The typedef for string
String Words[MAX_WORDS - 1]; // This array will hold
our words
int Count; //word count
// This will load
our file
void LoadFile()
{
char C; //Used to find EOF
ifstream Datfile; //The in file
Count=0; //Set
count to 0
// Open the data file
Datfile.open("words.dat");
//Loop till
the end of file
while((C=Datfile.peek()) != EOF)
{
// Get the next word and then increment Count
Datfile>>Words[Count++];
// If we
surpass the max exit and tell the user
if(Count > MAX_WORDS - 1)
{
cout<<endl<<"Too many words in
the file, stopping with "
<<MAX_WORDS<<"
Words."<<endl;
Count = MAX_WORDS;
break;
}
}
// We need to
subtract one to get the correct number of words
Count--;
// Close the
data file
Datfile.close();
}
// main4b.cpp
// This contains the program for adding and removing words
// to the hangman datfile.
// Copyright (c) 1998 Forest J. Handford
//////////////////////////////////////////////////////////
#include
"loadfile.h" // For LoadFile() and headers.
#include <stdlib.h> // For toupper()
#include <string.h> // For strcpy() and strcmp()
void WriteWords(); // Prototype
// The main function
to our editer
void main()
{
LoadFile(); // Load the file
ofstream
DatFile; //The out file
char Answer; //A Y or N value
char Word[MAX_WORD_SIZE]; //This will hold a word
int Size; //This will hold the
strings size
int Loop; // This will hold a
subscript
WriteWords();
cout<<endl<<endl<<"Would
you like to add any words (Yes or No)? ";
cin>>Answer;
// Loop to
take new words
while (toupper(Answer) == 'Y')
{
cout<<"What word would you like to enter,
Please keep it below "
<<endl<<MAX_WORD_SIZE<<"
Charachters: ";
cin>>Word;
Size = strlen(Word);
// Make the
word lower case
for(int Loop = 0; Size + 1 > Loop; Loop++)
{
Word[Loop] = tolower(Word[Loop]);
}
strcpy(Words[Count++],Word);
cout<<endl<<"Would you like to add another word
(Yes or No)? ";
cin>>Answer;
}
cout<<endl<<"Would
you like to remove a word (Yes or No)? ";
cin>>Answer;
// Loop to
remove words
while (toupper(Answer) == 'Y')
{
cout<<"What word do you want to remove?
";
cin>>Word;
Size = strlen(Word);
// Make the
word lower case
for(int Loop = 0; Loop < Size +1; Loop++)
{
Word[Loop] = tolower(Word[Loop]);
}
// Look for
the word and if found remove it
for (Loop = 0; Loop < Count; Loop++)
{
// if strings are = remove it
if (strcmp(Words[Loop],Word) == 0)
{
// adjust where the words are and reduce
count's size
strcpy(Words[Loop],Words[--Count]);
strcpy(Words[Count],""); //
replace with nothing
break;
}
}
cout<<endl<<"Would you like to remove another
word (Yes or No)? ";
cin>>Answer;
}
DatFile.open("words.dat");
//Open the file
//Save the words
for(Loop=0; Loop < Count - 1; Loop++)
{
DatFile<<Words[Loop];
DatFile<<"\t";
if (++Loop > Count) break;
DatFile<<Words[Loop];
DatFile<<"\t";
if (++Loop > Count) break;
DatFile<<Words[Loop];
DatFile<<"\t";
if (++Loop > Count) break;
DatFile<<Words[Loop];
DatFile<<"\t";
if (++Loop > Count) break;
DatFile<<Words[Loop];
DatFile<<"\n";
}
DatFile.close(); //Close the file
WriteWords(); //Write the words
cout<<endl<<endl<<"Good Bye"<<endl;
}
// This will display
all the words
void WriteWords()
{
cout<<"The following are words in the file:
"<<endl<<endl;
for(int
Loop=0; Loop < Count - 1; Loop++)
{
cout<<Words[Loop]<<"\t";
if (++Loop > Count) break;
cout<<Words[Loop]<<"\t";
if (++Loop > Count) break;
cout<<Words[Loop]<<"\t";
if (++Loop > Count) break;
cout<<Words[Loop]<<"\t";
if (++Loop > Count) break;
cout<<Words[Loop]<<"\n";
}
}
In the next Chapter we will make a role playing game to work on classes. This will lead up to the chapter after that, where we will create a strategy game.