Amazon Honor System Click Here to Pay Learn More

by Forest J. Handford

In this chapter we will learn about Object Oriented Programming (OOP) through C++ classes.  Using Classes we will then build a primitive Strategy game that will lead to a far superior one.

Currently our college professors say that the best type of programming is object oriented programming.  So far we have only done proceduralprogramming, which used to be considered the best. That was before OOP was invented. C is strictly procedural, but C++ allows OOP. Many people say that the millennium bug would be much easier to fix if the programmers had been using an OOP language.

The struct was the C version of the class.  A struct is a grouping of variables.  Here is an example:
struct SBox
{
   char Color[20];
   int Height;
   int Width;
   int Length;
};

The most annoying thing about classes and struct can be the semicolon that must follow the closing brace.  Now lets look at how to access a struct:
struct SBox
{
   char Color[20];
   int Height;
   int Width;
   int Length;
};

int main()
{
   SBox BoomBox;

   BoomBox.Height = 10;
   BoomBox.Width = 50;
   BoomBox.Length = 20;
   BoomBox.Color = "Neon Yellow"
}

Then there was class.  Classes allow us privacy.  Privacy what do I mean privacy?  structs only had public members.  This meant that any code could directly access the members of the struct.  Classes allow us to decide the access privileges of the other functions and classes in our programs.  Consider the following:
class CFood
{
private:
   int Weight;
   int Calories;
   char Name[20];
public:
   int Age;
};

If we have an object with the above class only class members could access the private members.  So say somewhere in my main function I declared a CFood object called Carrot.  In the main function I couldn't say Carrot.Weight = 12.  To access the class members we will create public functions.  Let's add to CFood:
class CFood
{
private:
   int Weight;
   int Calories;
   char Name[20];
   int Age;
 
public:

   void GiveValues()
   {
      cout<<"What is the name of your food? "<<endl;
      cin>>Name;
      cout<<"How many calories does a "<<Name<<" have? ";
      cin>>Calories;
      cout<<"How many ounces is your "<<Name<<"? ";
      cin>>Weight;
      cout<<"How old is your "<<Name<<"? ";
      cin>>Age;
   }
};

Now in our main function we can access the members by typing Carrot.GiveValues() .  Two important class functions that you can create are called the constructor and the destructor.  We will only go over the constructor in this chapter.

Say you want to give the class members default values or have the user enter values for the members when ever objects are created.  That is what the constructor is for.  Every time a class is created, after the memory is allocated, if a constructor is defined it is executed.  Review the following:

class CMonster
{
private:
   int HitPoints;
   int Armor;
   char Name[20];
   int Age;

public:
   CMonster()
   {
      cout<<"What is the name of your Monster? "<<endl;
      cin>>Name;
      cout<<"How many hit points does a "<<Name<<" have? ";
      cin>>HitPoints;
      cout<<"How much armor does your "<<Name<<" have? ";
      cin>>Armor;
      Age = 1;
   }

   void GiveValues()
   {
      cout<<"What is the name of your Monster? "<<endl;
      cin>>Name;
      cout<<"How many hit points does a "<<Name<<" have? ";
      cin>>HitPoints;
      cout<<"How much armor does your "<<Name<<" have? ";
      cin>>Armor;
      cout<<"How old is your "<<Name<<"? ";
      cin>>Age;
   }
};

Note that constructors, as well as destructors, do not have return types because they aren't allowed to return anything.  Constructors must have the same name as the class.

Classes can have classes within themselves.  Sometimes we want to allow certain functions or classes access to the private members of a class.  This is why we have friends.  Let's say we have a void Function() that we want to have access to.  Using our CMonster example we would do the following:
class CMonster
{
friend void function();
private:
   int HitPoints;
   int Armor;
   char Name[20];
   int Age;

public:
   CMonster()
   {
      cout<<"What is the name of your Monster? "<<endl;
      cin>>Name;
      cout<<"How many hit points does a "<<Name<<" have? ";
      cin>>HitPoints;
      cout<<"How much armor does your "<<Name<<" have? ";
      cin>>Armor;
      Age = 1;
   }

   void GiveValues()
   {
      cout<<"What is the name of your Monster? "<<endl;
      cin>>Name;
      cout<<"How many hit points does a "<<Name<<" have? ";
      cin>>HitPoints;
      cout<<"How much armor does your "<<Name<<" have? ";
      cin>>Armor;
      cout<<"How old is your "<<Name<<"? ";
      cin>>Age;
   }
};

If we wanted our CFood function to have access to the private members of another class we would write the following in the class's definition:
friend CFood;

You may be wondering why I have been using C in front of the name for classes and S in front of the name for structs.  Many C and C++ writers always use an H.  I feel that the C or S are more meaningful so I use them instead.

The :? operator.  This is a simple version of true and false.  Consider the following:
cout<<"Your pig" << (Size>1 : "s need"  ? " needs")<< " food."<<endl;

If Size is bigger than 1 then one the output is:
Your pigs need food.

If Size is less than 1 the output would be:
Your pig needs food.

Since I now own a copy of Visual C++ 6.0 , you will see bool types in this and many other future programs. bool is the smallest a data structure can be. It's only values can be 0 or 1. I usually use 1 for Yes and True, while using 0 for False or No, but we can use it for other things. If your compiler can't use bool, you can use int instead.

The last thing we need to cover before the game is three preprocessor statements.  cpp files compile into obj files.  The obj or object files are then linked together.  Compilers will not allow headers or classes to be defined more than once.  Consider the following:
#ifndef County5a_h
#define Country5a_h

struct Square
{
   int Width;
   int Height;
};

#endif

If the above code is written in a header included by multiple cpp files it will only be included in one obj file per program.  These statements don't accept periods so use underscores instead.

Now here is Two Player Conquest:

< main > < header > < program >

country5a.h:
// country5a.h
// This will hold the class definitions for countries
// Copyright (c) 1998 Forest J. Handford
/////////////////////////////////////////////////////

#ifndef Country5a_h
#define Country5a_h

#define MAX_PLAYERS 2
#define TRUE 1
#define FALSE 0

class CCountries
{
private:
 class CPlayer
 {
  friend CCountries; // Give CCountries access
  int Armies;
  int Money;
  int Territory;
  int Technology;
  int UpgradeCost;
 
  char Name[15];
  CPlayer()
  {
   Armies = 5;
   Money = 5;
   Territory = 5;
   Technology = 1;
   UpgradeCost = 5;
  }
 public:

  // This will sell land
  void Grow()
  {
   char YorN = 'y'; // For Yes or No answers

   // Loop as long as they want to grow
   for(int Count=0; tolower(YorN) == 'y'; Count++)
   {
    // They most have at least one army for every territory
    if (Armies <= Territory)
    {
     cout<<"You need more armies for more land."<<endl;
     break;
    }
    // Sell the land and tell the players
    else if(Money > 0)
    {
     Money -= 1;
     Territory += 1;
     cout<<"You now have "<<Territory
      <<" States and "<<Money<<" money."<<endl;
     // Don't stay here if they are out of land or money
     if((Armies <= Territory) || (Money <= 0))
     {
      break;
     }
     cout<<"Would you like to buy another (Yes or No)?";
     cin>>YorN;
    }
    // If they are out of money tell them and exit
    else
    {
     cout<<"You are out of money!"<<endl;
     break;
    }
   }

  }

  // This will check for to many territories
  void CountryLoss()
  {
   if(Armies < Territory)
   {
    cout<<"Sorry "<<Name<<", you don't have enough armies to keep "
     <<"your territories!  They are"
     <<endl<<"reduced to "<<Armies<<"."
     <<endl;
    Territory = Armies;
   }
  }
 };
 

public:
 CPlayer Players[MAX_PLAYERS];
 
 
 void Upgrade(bool Player)
 {
  char YorN = 'y';

  // Loop till the user is out of money or is bored
  while(tolower(YorN) == 'y')
  {
   // Take their money if they have any
   if(Players[Player].Money >= Players[Player].UpgradeCost)
   {
    Players[Player].Money -= Players[Player].UpgradeCost;
    Players[Player].UpgradeCost *= 2;
    Players[Player].Technology += 1;
    cout<<"You now have "<<Players[Player].Technology
     <<" Upgrades and "<<Players[Player].Money<<" money."<<endl;
    cout<<"Upgrades now cost you : "<<Players[Player].UpgradeCost<<"."<<endl;
   }
   else // Scold them for having no money
   {
    cout<<"You don't have enough money.  You need "<<Players[Player].UpgradeCost<<"."
     <<endl;
   }
   // break if they run out of money
   if(Players[Player].Money <= Players[Player].UpgradeCost)
   {
    break;
   }

   // ask if they want more
   cout<<"Would you like to upgrade again (Yes or No)? ";
   cin>>YorN;
  }
 }
 
 void Shrink(bool Player)
 {
  char YorN = 'y';

  while(tolower(YorN) == 'y')
  {
   if(Players[Player].Territory > 0)
   {
    Players[Player].Money += 1;
    Players[Player].Territory -= 1;
    cout<<"You now have "<<Players[Player].Territory
     <<" States and "<<Players[Player].Money<<" money."<<endl;
    cout<<"Would you like to buy another (YorN)?";
    cin>>YorN;
   }
   else
   {
    cout<<"You are out of money!"<<endl;
    break;
   }
  }
 }

 void AddStuff(bool Player)
 {
  Players[Player].Armies += Players[Player].Territory;
  Players[Player].Money += Players[Player].Territory;
  WriteName(Player);
  cout<<" now has "<<Players[Player].Armies
   <<" armies and "<<Players[Player].Money<<" money from ";
  WriteName(Player);
  cout<<"'s states."<<endl<<endl;
 }
 void WriteName(bool C)
 {
  cout<<Players[C].Name;
 }

 void Dead(bool Victim)
 {
  WriteName(Victim);
  cout<<" you are dead!"<<endl;
  WriteName(Victim == 0 ? 1 : 0);
  cout<<" you have won!"<<endl<<endl;
 }

public:
 CCountries()
 {
  for(int Count = 0; Count < 2; Count ++)
  {
   cout<<"Player "<<Count + 1<<" What is your name? ";
   cin>>Players[Count].Name;
   cout<<endl;
  }

 }

 bool Attack(bool Attacker, bool Victim)
 {
  int AttackerArmies; //This will hold the attacker's # of armies
  int VictimArmies; //This will hold the Victim's # of armies
  char YorN = 'Y';

  while(toupper(YorN) == 'Y')
  {
   AttackerArmies = Players[Attacker].Armies - (Players[Victim].Armies * Players[Victim].Technology / Players[Attacker].Armies * Players[Attacker].Technology);
   VictimArmies = Players[Victim].Armies - (Players[Attacker].Armies * Players[Attacker].Technology / Players[Victim].Armies * Players[Victim].Technology);
   Players[Attacker].Armies = AttackerArmies;
   Players[Victim].Armies = VictimArmies;
 
   if(Players[Victim].Armies < 1)
   {
    Dead(Victim);
   }
 
   if(Players[Attacker].Armies < 1)
   {
    Dead(Attacker);
    return FALSE; // Flag end of Game
   }
 
   if(Players[Victim].Armies < 1)
   {
    return FALSE; // Flag end of Game
   }
 
   Players[Victim].CountryLoss();
   Players[Attacker].CountryLoss();
   WriteName(Attacker);
   cout<<" now has "<<Players[Attacker].Armies<<" armies."<<endl;
   WriteName(Victim);
   cout<<" now has "<<Players[Victim].Armies<<" armies."<<endl;
   WriteName(Attacker);
   cout<<", Would you like to attack again (Yes or No)? ";
   cin>>YorN;

  }
  return TRUE; // Flag success
 }
};

#endif


main5a.cpp:
// main5a.cpp
// This holds the main function for the first Conquest game of
// the C++ Game Programmer's Tutorial.
// Copyright (c) Forest J. Handford 1998
//////////////////////////////////////////////////////////////

#include <iostream.h>
#include <ctype.h>
#include "Country5a.h"

void main()
{
 char Answer; // This will hold a Y or N

 cout<<endl<<"\tWelcome to Conquest"<<endl
  <<"\t\tBy Forest J. Handford"<<endl
  <<"\t\tCopyright (c) 1998"<<endl<<endl;

 CCountries Countries; // Create Countries

 // Loop till the Continue is false
 for(bool Player = 0,Continue = TRUE; Continue == TRUE; Player = (Player == 1 ? 0 : 1))
 {
  Answer = 'l'; // set answer to not = 'p'

  Countries.WriteName(Player);  // Ask the player to sit
  cout<<" take your seat."<<endl;

  // Loop till player passes
  while (tolower(Answer) != 'p' && Continue == TRUE)
  {
   cout<<"Would you like to Upgrade, Grow, Shrink, Attack or Pass? ";
   cin>>Answer;
   if ( tolower(Answer) == 'a')
   {
    Continue = Countries.Attack(Player, Player == 1 ? 0 : 1);
    if(Continue == TRUE)
    {
     cout<<"Would you like to Upgrade, Grow, Shrink or Pass? ";
     cin>>Answer;
     if (tolower(Answer) == 'u')
     {
      Countries.Upgrade(Player);
      cout<<"Would you like to Grow, Shrink or Pass? ";
      cin>>Answer;
      if(tolower(Answer) == 'g')
      {
       Countries.Players[Player].Grow();
      }
      else if(tolower(Answer) == 's')
      {
       Countries.Shrink(Player);
      }
     }
     else if(tolower(Answer) == 'g')
     {
      Countries.Players[Player].Grow();
      cout<<"Would you like to Upgrade or Pass? ";
      cin>>Answer;
      if(tolower(Answer) == 'u')
      {
       Countries.Upgrade(Player);
      }
     }
     else if(tolower(Answer) == 's')
     {
      Countries.Shrink(Player);
      cout<<"Would you like to Upgrade or Pass? ";
      cin>>Answer;
      if(tolower(Answer) == 'u')
      {
       Countries.Upgrade(Player);
      }
     }

     Answer = 'p';
    }
   }
   else if(tolower(Answer) == 'u')
   {
    Countries.Upgrade(Player);
    cout<<"Would you like to Grow, Shrink or Pass? ";
    cin>>Answer;
    if(tolower(Answer) == 'g')
    {
     Countries.Players[Player].Grow();
    }
    else if(tolower(Answer) == 's')
    {
     Countries.Shrink(Player);
    }

    Answer = 'p';
   }
   else if(tolower(Answer) == 'g')
   {
    Countries.Players[Player].Grow();
    cout<<"Would you like to Upgrade or Pass? ";
    cin>>Answer;
    if(tolower(Answer) == 'u')
    {
     Countries.Upgrade(Player);
    }

    Answer = 'p';
   }
   else if(tolower(Answer) == 's')
   {
    Countries.Shrink(Player);
    cout<<"Would you like to Upgrade or Pass? ";
    cin>>Answer;
    if(tolower(Answer) == 'u')
    {
     Countries.Upgrade(Player);
    }
    Answer = 'p';
   }
   else if(tolower(Answer) == 'p')
   {
    Answer = 'p';
   }
   else
   {
    cout<<"Sorry, bad input . . . try again"<<endl;
   }
  }
  if(Continue == FALSE)
  {
   break;
  }
  Countries.AddStuff(Player);
 }
 // Say Good bye.
 cout<<"Thanks for Playing and Good Bye."<<endl;
}

2 Player Conquest - I think that we have done enough for this chapter.  In the next chapter you'll learn about pointers, queues, and destructors as we make a more advanced conquest game.

PREVIOUS CHAPTER       HOME       NEXT CHAPTER

Amazon Honor System Click Here to Pay Learn More