The first attempt at Sports Hangman
Incoherent and incomplete class design
Polluted namespace
Long winded code going somewhere slowly
Missing exceptions
// SportHangman1.cpp : Defines the entry point for the console application.
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <cctype>
#include <vector>
// Good practice: idenfify usage within library
#include <algorithm> // for random_shuffle
using namespace std;
// Poor practice: global constants
const int NUM = 15;
const int MAX = 5;
const int BASEBALL = 1;
const int FOOTBALL = 2;
const int BASKETBALL = 3;
// Poor practice: global variables
// Use a STL vector to store the word list and add to it
vector<string> newwordlist;
//vector<string> ::iterator targetword;
// Poor Practice: variable list without compile calculated NUM constant
const string wordlist[NUM] = {"padres", "giants", "rockies",
"dodgers", "diamondbacks", "lakers", "pistons", "spurs",
"pacers", "kings", "browns", "cowboys", "titans", "niners",
"panthers"};
// Classes are undeveloped, not encapsulated, and not fully implemented
// Poor practice: non-encapsulated class data
// Poor practice: global constant for setting class name limits
// non-usage order in declaration, should be friends, public, protected, private
// use multiple classes
//base class
class Athlete{
private:
char firstname[MAX];
char lastname[MAX];
public:
char position[MAX];
char team[MAX];
};
// poor practice: non-typed return on class methods
// no implementation of methods
// no encapsulation of data for inherited methods
// no polymorphism across classes for common api -- set() method
// no helper stream classes for debugging
// logic of methods found in main routine with local variables
// inheritance
class BaseballPlayer:public Athlete{
public:
void timeofyear();
};
class FootballPlayer:public Athlete{
public:
void numberofgames();
};
class BasketballPlayer:public Athlete{
public:
void numberofplayers();
};
int main() {
srand(time(0));
char play;
string newword;
string target;
int i = 0;
int sport;
char timeofyear;
int numberofgames;
int numberofplayers;
// Populate the vector with the team list
while (i < NUM) {
newwordlist.push_back(wordlist[i]);
i = i + 1;
}
// See if this worked
cout << "new word list holds " << newwordlist.size() << " words.\n\n";
// Add some words to the list, dynamically size the vector
do {
cout << "Add another team to the list <y/n>? ";
cin >> play;
if (play == 'y'){
cout << " Enter new team name for the list: ";
cin >> newword;
newwordlist.push_back(newword);
i = i + 1;
}
}
while (play != 'n');
// See if this worked
cout << "new team list holds " << newwordlist.size() << " teams.\n\n";
// Only accept y or n for an answer, exception handling
do {
cout << "Will you play a word game? <y/n> ";
cin >> play;
// conversion of int to char; possible loss of data
play = tolower(play);
}
while (play != 'y' && play != 'n');
while (play == 'y') {
// Shuffle the order each time and just get the first word
random_shuffle(newwordlist.begin(), newwordlist.end() );
target = newwordlist[0];
// print this out just to see how it is working
cout << " ==> vector word is: " << newwordlist[0] << "\n";
int length = target.length();
string attempt(length, '-');
string badchars;
int guesses = 6;
cout << "Enter my secret team name. It has " << length
<< " letters, and you guess\n"
<< "one letter at a time. You get " << guesses
<< " wrong guesses.\n";
cout << "Your word: " << attempt << endl;
while (guesses > 0 && attempt != target) {
char letter;
cout << "Guess a letter: ";
cin >> letter;
if (badchars.find(letter) != string::npos
|| attempt.find(letter) != string::npos) {
cout << "You already guessed that. Try again.\n";
continue;
}
int loc = target.find(letter);
// signed / unsigned mismatch warning
if (loc == string::npos) {
cout << "Oh, bad guess!\n";
--guesses;
badchars += letter; // add to string
}
else {
cout << "Good guess!\n";
attempt[loc]=letter;
// check if letter appears again
loc = target.find(letter, loc + 1);
// signed / unsigned mismatch
while (loc != string::npos) {
attempt[loc]=letter;
loc = target.find(letter, loc + 1);
}
}
cout << "Your word: " << attempt << endl;
if (attempt != target) {
if (badchars.length() > 0)
cout << "Bad choices: " << badchars << endl;
cout << guesses << " bad guesses left\n";
}
}
// I have not finished this area, see the other project for inheritance
if (guesses > 0){
cout << "That's right!\n";
cout << "What Sport is this team from? <1-baseball, 2-football, 3-basketball> : ";
cin >> sport;
if (sport == BASEBALL) {
cout << "Enter the time of year baseball is played: ";
cin >> timeofyear;
}
else if (sport == FOOTBALL) {
cout << "Enter the number of football games played: ";
cin >> numberofgames;
}
else { // (sport == BASKETBALL){
cout << "Enter the number of players on the team: ";
cin >> numberofplayers;
}
}
else
cout << "Sorry, the word is " << target << ".\n";
// Only accept y or n for an answer, exception handling
do {
cout << "\nWill you play another? <y/n> ";
cin >> play;
// conversion of int to char; possible loss of data
play = tolower(play);
}
while (play != 'y' && play != 'n');
}
cout << "Bye\n";
return 0;
}
void BasketballPlayer::numberofplayers()
{
}
The second attempt at Sports Hangman
Class code begins to emerge
Class design mistakes begin to show up
Main code begins to disappear and clean up
// SportHangman2.cpp : Defines the entry point for the console application.
#include <iostream>
#include <string>
//#include <cstdlib> // srand()
#include <ctime> // time()
#include <vector>
#include <algorithm> // random_shuffle
using namespace std;
class Athlete {
friend ostream & operator<<( ostream & os, const Athlete & athlete );
public:
static const string KNOWN_TEAMS[];
static const int KNOWN_TEAMS_MAX;
static void update_teams();
static void show_teams();
static const vector<string> & get_teams() { return teams; };
Athlete() {};
virtual void set() = 0;
virtual void show( ostream & os ) const = 0;
private:
static vector<string> teams;
string firstname;
string lastname;
string position;
string team;
};
const string Athlete::KNOWN_TEAMS[] = {"padres", "giants", "rockies",
"dodgers", "diamondbacks", "lakers", "pistons", "spurs",
"pacers", "kings", "browns", "cowboys", "titans", "niners",
"panthers"};
// Variable length records means this MAX must be manually done
const int Athlete::KNOWN_TEAMS_MAX = 15;
vector<string> Athlete::teams;
void Athlete::update_teams() {
// Populate the vector with the team list
int index = 0;
if ( teams.size() == 0 ) {
while (index < KNOWN_TEAMS_MAX) {
teams.push_back(KNOWN_TEAMS[index]);
++index;
}
}
cout << "Team list now holds " << teams.size() << " words.\n\n";
// Add some words to the list, dynamically size the vector
char play;
string team;
do {
cout << "Add another team to the list ? ";
cin >> play;
if (play == 'y'){
cout << " Enter new team name for the list: ";
cin >> team;
teams.push_back(team);
}
} while (play != 'n');
// See if this worked
cout << "new team list holds " << teams.size() << " teams.\n\n";
}
void Athlete::show_teams() {
const int MAX = teams.size();
const int NL = 5;
string divider;
cout << "Teams are:\n";
for ( int index = 0; index < MAX; ++index) {
divider = (index % NL) ? " " : "\n";
cout << teams[index] << divider;
}
}
void Athlete::set() {
cout << "Enter First name\n";
cin >> firstname;
cout << "Enter Last name\n";
cin >> lastname;
cout << "Enter team name\n";
cin >> team;
cout << "Enter team position\n";
cin >> position;
}
void Athlete::show (ostream & os) const {
os << "Name: " << firstname << " " << lastname << "\n"
<< "Team: " << team << " position: " << position << "\n";
}
ostream & operator<<( ostream & os, const Athlete & athlete ) {
athlete.show(os);
return os;
}
// inheritance
class BaseballPlayer : public Athlete {
friend ostream & operator<<( ostream & os, const BaseballPlayer & player );
public:
virtual void set();
virtual void show( ostream & os ) const;
private:
char timeofyear;
};
void BaseballPlayer::set() {
Athlete::set();
cout << "Enter the time of year\n";
cin >> timeofyear;
}
void BaseballPlayer::show( ostream & os ) const {
Athlete::show(os);
os << "Time of Year: " << timeofyear << "\n";
}
ostream & operator<<( ostream & os, const BaseballPlayer & player ) {
player.show(os);
return os;
}
class FootballPlayer : public Athlete {
friend ostream & operator<<( ostream & os, const FootballPlayer & player );
public:
virtual void set();
virtual void show( ostream & os ) const;
private:
int numberofgames;
};
void FootballPlayer::set() {
Athlete::set();
cout << "Enter the number of games\n";
cin >> numberofgames;
}
void FootballPlayer::show( ostream & os ) const {
Athlete::show(os);
os << "Number of Games: " << numberofgames << "\n";
}
ostream & operator<<( ostream & os, const FootballPlayer & player ) {
player.show(os);
return os;
}
class BasketballPlayer : public Athlete {
friend ostream & operator<<( ostream & os, const BasketballPlayer & player );
public:
virtual void set();
virtual void show( ostream & os ) const;
private:
int numberofplayers;
};
void BasketballPlayer::set() {
Athlete::set();
cout << "Enter the number of players\n";
cin >> numberofplayers;
}
void BasketballPlayer::show( ostream & os ) const {
Athlete::show(os);
os << "Number of Players: " << numberofplayers << "\n";
}
ostream & operator<<( ostream & os, const BasketballPlayer & player ) {
player.show(os);
return os;
}
int main() {
// get the time at the present moment and set the random seed to the current time
// ... guarantees each run will be a unique random sequence
srand(time(0));
enum { BASEBALL = 1, FOOTBALL, BASKETBALL };
Athlete::update_teams();
Athlete::show_teams();
const vector<string> & teams = Athlete::get_teams();
vector<string> newwordlist(teams);
const int MAX_GUESSES = 6;
char play;
string newword;
string target;
int sport;
Athlete * player;
vector<Athlete *> players;
// Only accept y or n for an answer, exception handling
do {
cout << "Will you play a word game? <y/n> ";
cin >> play;
play = static_cast<char>(tolower(play));
} while (play != 'y' && play != 'n');
while (play == 'y') {
// Shuffle the order each time and just get the first word
random_shuffle(newwordlist.begin(), newwordlist.end() );
target = newwordlist[0];
// print this out just to see how it is working
cout << " ==> vector word is: " << newwordlist[0] << "\n";
int length = target.length();
string attempt(length, '-');
string badchars;
int guesses = MAX_GUESSES;
cout << "Enter my secret team name. It has " << length
<< " letters, and you guess\n"
<< "one letter at a time. You get " << guesses
<< " wrong guesses.\n";
cout << "Your word: " << attempt << endl;
while (guesses > 0 && attempt != target) {
char letter;
cout << "Guess a letter: ";
cin >> letter;
if (badchars.find(letter) != string::npos
|| attempt.find(letter) != string::npos) {
cout << "You already guessed that. Try again.\n";
continue;
}
unsigned int loc = target.find(letter);
if (loc == string::npos) {
cout << "Oh, bad guess!\n";
--guesses;
badchars += letter; // add to string
}
else {
cout << "Good guess!\n";
attempt[loc]=letter;
// check if letter appears again
loc = target.find(letter, loc + 1);
while (loc != string::npos) {
attempt[loc]=letter;
loc = target.find(letter, loc + 1);
}
}
cout << "Your word: " << attempt << endl;
if (attempt != target) {
if (badchars.length() > 0)
cout << "Bad choices: " << badchars << endl;
cout << guesses << " bad guesses left\n";
}
}
if (guesses > 0){
cout << "That's right!\n";
cout << "What Sport is this team from? <1-baseball, 2-football, 3-basketball> : ";
cin >> sport;
switch (sport) {
case BASEBALL : player = new BaseballPlayer();
player->set();
break;
case FOOTBALL : player = new FootballPlayer();
player->set();
break;
case BASKETBALL : player = new BasketballPlayer();
player->set();
break;
default : cout << "Invalid choice, player not added\n";
player = NULL;
break;
}
if ( player != NULL ) {
players.push_back(player);
player = NULL;
}
}
else
cout << "Sorry, the word is " << target << ".\n";
// Only accept y or n for an answer, exception handling
do {
cout << "\nWill you play another? <y/n> ";
cin >> play;
play = static_cast<char>(tolower(play));
}
while (play != 'y' && play != 'n');
}
// show players, deallocate memory
const vector<Athlete*>::iterator END = players.end();
for (vector<Athlete*>::iterator it = players.begin(); it != END; ++it) {
cout << **it;
// OR (*it)->show(cout);
delete *it;
}
cout << "Bye\n";
return 0;
}
Hangman with a few words
The Game is an Object
The Word is an Object
The exception checks for valid entries
Each code piece is manageable
// Hangman.cpp : Defines the entry point for the console application.
#include <&ctime> // time()
#include <&string>
#include <&vector>
#include <&exception>
#include <&iostream> // cout, cin, endl
using namespace std;
class Wordlist {
public:
vector<&string> words;
Wordlist ();
string & getNextWord();
private:
const static int NUM_WORD_LIST = 26;
};
Wordlist::Wordlist() {
const string list[NUM_WORD_LIST] = {"apiary", "beetle", "cereal",
"danger", "ensign", "florid", "garage", "health", "insult",
"jackal", "keeper", "loaner", "manage", "nonce", "onset",
"plaid", "quilt", "remote", "stolid", "train", "useful",
"valid", "whence", "xenon", "yearn", "zippy"};
srand((unsigned int)time(0));
for (int index=0; index < NUM_WORD_LIST; index++)
words.push_back(list[index]);
}
string & Wordlist::getNextWord() {
return words[rand() % NUM_WORD_LIST];
}
class Game {
public:
Game ();
~Game ();
void playGame ();
private:
Wordlist wordlist;
void displayStartMessage (int length);
void getEntry (char &);
void validateEntry (const char);
int checkGuess (const char, const size_t);
string currentWord;
string badGuessesList;
string secretWord;
enum guesses {
BAD_GUESS = 0,
GOOD_GUESS
};
int guessesCount;
int wordLength;
char letterEntered;
};
Game::Game () {
guessesCount = 6;
}
Game::~Game () {
}
void Game::displayStartMessage(int wordLength) {
cout << "Guess my secret word. It has " << wordLength
<< " letters, and you guess\n"
<< "one letter at a time. You get " << guessesCount
<< " wrong guesses.\n";
cout << "Your word: " << secretWord << endl;
}
int Game::checkGuess (const char letter, const size_t letterPosition) {
if (badGuessesList.find(letter) != string::npos
|| secretWord.find(letter) != string::npos) {
cout << "You already guessed that. Try again.\n";
return BAD_GUESS;
}
if (letterPosition == string::npos) {
cout << "Oh, bad guess!\n";
--guessesCount;
badGuessesList += letter; // add to string
return BAD_GUESS;
}
return GOOD_GUESS;
}
void Game::getEntry (char & letter) {
try {
cin >> letter;
letter = static_cast<&char>(tolower(letter));
if (!isalpha(letter))
throw "Please enter an alpha character ";
}
catch (const char * s) {
cout << s << endl;
letter = '0';
}
catch (...) {
cout << "Please enter an alpha character " << endl;
}
}
void Game::validateEntry (const char letter) {
size_t letterPosition = currentWord.find(letter);
if (checkGuess(letter, letterPosition) == GOOD_GUESS) {
cout << "Good guess!\n";
secretWord[letterPosition]=letter;
letterPosition = currentWord.find(letter, letterPosition + 1);
while (letterPosition != string::npos)
{
secretWord[letterPosition]=letter;
letterPosition = currentWord.find(letter, letterPosition + 1);
}
}
cout << "Your word: " << secretWord << endl;
if (secretWord != currentWord) {
if (badGuessesList.length() > 0)
cout << "Bad choices: " << badGuessesList << endl;
cout << guessesCount << " bad guesses left\n";
}
}
void Game::playGame () {
currentWord = wordlist.getNextWord();
wordLength = (int) currentWord.length();
secretWord.assign (wordLength, '-');
displayStartMessage (wordLength);
while (guessesCount > 0 && secretWord != currentWord) {
cout << "Guess a letter: ";
getEntry (letterEntered);
if (letterEntered != '0')
validateEntry (letterEntered);
}
if (guessesCount > 0)
cout << "That's right!\n";
else
cout << "Sorry, the word is " << currentWord << ".\n";
}
int main() {
char play;
cout << "Will you play a word game? <&y/n> ";
cin >> play;
play = static_cast<&char>(tolower(play));
while (play == 'y') {
Game game;
game.playGame();
cout << "Will you play another? <&y/n> ";
cin >> play;
play = static_cast<&char>(tolower(play));
}
cout << "Bye\n";
return 0;
}