by Forest J. Handford

This chapter will cover queues and pointers..
 


In C++ we have the ability to access memory directly through pointers.  Pointers hold the address for the memory that it points to.  Pointers are made to only point to one type.  Consider the following code:
int *Ptr;
int Number = 32;
*Ptr = Number;
cout<<*Ptr;

output:
32

The above code sets up an integer pointer.  It then is set to point to Number.  If you look at the address it will look similar to:
0x0066fddc

The above may look like gibberish but it is actually a hexadecimal number.  The hexadecimal number system is base 16, 0 - f.  hexadecimal is used often because all binary values can easily be translated to hexadecimal.  Consider the following:

Base 10 value Base 2 or binary value Base 16 or hexadecimal value
45 101101 2d

To access the values in the address a pointer points to, write an asterisk (*) in front of it.  To declare a pointer write it's type followed by an *, followed by it's name.

To access members of an object that a pointer uses you'll need the -> operator.  Consider the following:
class CPlayer
{
     int Score;
     char name[25];
}

CPlayer Player1;
Player1.Score = 20;
"Hello">>Player1.name;

CPlayer *Ptr;
Ptr = Player1;
cout<<Ptr->Score;

output:
20

In England if you told somebody to get in line they would look at you like you have three heads.  In England they use the word queue instead of line.  Consider that the next time your in a queue to see a movie.

A queue is a dynamic way to use memory.  In our next game we could make an array of twenty players and even if their are only two players twenty players worth of memory will be used by the program.  Instead of an array we will use a queue.  When a player joins, the game memory will be allocated for them.  When a player leaves the game the memory will be deallocated and returned to the operating system.  A queue is structured as follows:


Most queues don't point both ways but for our game they are necessary.  Front, Rear, Previous, and Link are all pointers to nodes.  If the node is at the front we make previous = 0 and Front = to the memory address of the front node.  To make a new node we will use the new operator.  To delete a node we will use the delete operator like this:
CPlayer *Player1 = new CPlayer;
delete Player1;

If the node is at the end we have the rear point to the node and Rear point to the rear node.  Here's code from our queue:
class CCountries
{
 class CPlayer
 {

  friend CCountries;

 private:

  CPlayer *Link;
  CPlayer *Previous;
  int Armies;
  int Money;
  int Territory;
  int Technology;
  int UpgradeCost;
  char Name[15];

 };

private:

 CPlayer *Rear;

public:

 CPlayer *Front;

 //Set the Front and rear to point to 0
 //////////////////////////////////////
 CCountries()
 {
  Front = 0; //make front null
  Rear = 0; //make rear null

  char Exit = 'N'; // Y or N value

  AddPlayer(Total);

  while(toupper(Exit) != 'Y')
  {
   Total++;
   AddPlayer(Total);
   cout<<"Are you the last player ((Y)es or (N)o)? ";
   cin>>Exit;
  }
 }

 //The destructor that deletes any nodes on the queue
 ////////////////////////////////////////////////////
 ~CCountries()
 {
  CPlayer *Current; //The current node to delete
  CPlayer *Next;  //The next node to delete

  Current = Front; //start Current in the front

  //Until the list is empty delete the nodes
  while(Current!=0)
  {
   Next = Current->Link; //setup the next node
   delete Current;   //delete the current node
   Current = Next;   //prepare for the next loop run
  }
 }
 

 //Inserts a Player at the rear
 /////////////////////////////
 void Enqueue(CPlayer Player)
 {
  CPlayer *Ptr;   //Make a Ptr for the new node
  Ptr = new CPlayer; // create a queuenode and point to it with Ptr

  *Ptr = Player;
  Ptr->Link = 0;   //start the pointer at 0
  Ptr->Previous = Rear; //point to the previous player

  //If the node isn't empty set the last link to point to the new node
  if (Front != 0)
   Rear->Link = Ptr;
  //else make the Front point to it.
  else
   Front = Ptr;
  //Make the rear point to the new node
  Rear = Ptr;
 }

 //Delete the first player and return the data
 /////////////////////////////////////////////
 CPlayer Dequeue()
 {
  CPlayer Player; //the return value
  CPlayer *Ptr; //Will point to the first node

  //If there are nodes delete the first one
  if (Front != 0)
  {
   Ptr = Front;  //Have the Pointer aim at the Front
   Player = *Ptr;  //Copy the player
   Front = Ptr->Link; //Make Front point to the next node in line
   delete Ptr;   //delete the node
   Front->Previous = 0; // set to 0
   if (Front==0)  //If the list is empty make the rear point to 0
    Rear = 0;
  }
  //else print an error
  else
   cout<<"Hey man, there aren't any Players here!"<<endl;

  return Player; //Return the deleted Player
 }

private:

 // This will Delete a Player
 ////////////////////////////
 bool Dead(CPlayer *Victim)
 {
  CPlayer *Current;

  cout<<Victim->Name<<" you are dead!"<<endl;

  // Check to make sure is is not the first entry
  if(Victim->Previous != 0)
  {
   Current = Victim->Previous;
   Current->Link = Victim->Link;
  }
  else // else change the rear
  {
   Front = Victim->Link;
  }

  // Check to make sure it is not the last entry
  if(Victim->Link != 0)
  {
   Current = Victim->Link;
   Current->Previous = Victim->Previous;
  }
  else // else change the Rear
  {
   Rear = Victim->Previous;
  }
 

  delete Victim;

  return FALSE;
 }

 // This adds a player
 void AddPlayer(int Total)
 {
  CPlayer *Ptr;   //Make a Ptr for the new node
  Ptr = new CPlayer; // create a queuenode and point to it with Ptr
  Ptr->Armies = 5;
  Ptr->Money = 5;
  Ptr->Territory = 5;
  Ptr->Technology = 1;
  Ptr->UpgradeCost = 5;

  cout<<"Player "<<Total<<" What is your name? ";
  cin>>Ptr->Name;

  Ptr->Link = 0;   //start the pointer at 0

  //If the node isn't empty, set the last link to point to the new node
  if (Front != 0)
  {
   Ptr->Previous = Rear;
   Rear->Link = Ptr;
  }
  //else make the Front point to it.
  else
  {
   Ptr->Previous = 0;
   Front = Ptr;
  }
  //Make the rear point to the new node
  Rear = Ptr;
 }
};

The biggest concern of queues is memory leaks.  A memory leak is when you create a node that isn't accessible.  Say we dequeued a node but forgot to delete it.  We would no longer have a pointer to it but it would still exist.  This can slowly eat away your memory until either your program crashes, your program exits, or your computer crashes.  If you use a Microsoft compiler the program will notice the problem and exit with an error.  If you use the Borland compiler your other memory and then your code stored in RAM will be overwritten, this will lead to the computer crashing.

The first version of Windows 95, it was riddled with memory leaks.  Your system would crash if you left it on for more than a day!  This is one of the big reasons why I turn off my PC at work when I'm ready to go home.

The easiest way I found to exit the game was through the void exit( int status ) function defined in stdlib.h.  Exit must be passed an int value.  All programs end with an integer value.  EXIT_SUCCESS is defined in stdlib.h and equals 0.  I'll use that to indicate that no error was encountered running the program.

To find out if pointers point to the same thing we can use the == operator.  Higher pointers have higher memory addresses and lower pointers have lower memory addresses.

The queue allows us to have as many players as patience and memory allows.  On my computer you would have to enter thousands of players before you ran out of memory.  I doubt you'll ever reach the maximum capacity of players.

As you will see, very little of the code is changed from the last program.  This saved me programming time.  Reuse code as often as possible.

Now here is Multiplayer Conquest:


< Header > < Main > < Program >

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

#ifndef Country6a_h
#define Country6a_h

#include <string.h>
#include <stdlib.h>

#define TRUE 1
#define FALSE 0

int Total = 1;  // A global count of the total players
int AddArmies = 5; // A global count of the number of armies to win after a kill
 

class CCountries
{
 class CPlayer
 {

  friend CCountries;

 private:

  CPlayer *Link;
  CPlayer *Previous;
  int Armies;
  int Money;
  int Territory;
  int Technology;
  int UpgradeCost;
  char Name[15];

  // 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:

  int ShowArmies()
  {
   return (Armies);
  }

  // This writes the name of the given player
  ///////////////////////////////////////////
  void WriteName()
  {
   cout<<Name;
  }

  // This will sell land to the player
  ////////////////////////////////////
  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 must 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 ((Y)es or (N)o)? ";
     cin>>YorN;
    }
    // If they are out of money tell them and exit
    else
    {
     cout<<"You are out of money!"<<endl;
     break;
    }
   }

  }

  // This will sell upgrades
  //////////////////////////
  void Upgrade()
  {
   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(Money >= UpgradeCost)
    {
     Money -= UpgradeCost;
     UpgradeCost *= 2;
     Technology += 1;
     cout<<"You now have "<<Technology
      <<" Upgrades and "<<Money<<" money."<<endl;
     cout<<"Upgrades now cost you : "<<UpgradeCost<<"."<<endl;
    }
    else // Scold them for having no money
    {
     cout<<"You don't have enough money.  You need "<<UpgradeCost<<"."
      <<endl;
    }
    // break if they run out of money
    if(Money <= UpgradeCost)
    {
     break;
    }

    // ask if they want more
    cout<<"Would you like to upgrade again ((Y)es or (N)o)? ";
    cin>>YorN;
   }
  }

  // This will sell land back
  ///////////////////////////
  void Shrink()
  {
   char YorN = 'y';

   while(tolower(YorN) == 'y')
   {
    if(Territory > 0)
    {
     Money += 1;
     Territory -= 1;
     cout<<"You now have "<<Territory
      <<" States and "<<Money<<" money."<<endl;
     cout<<"Would you like to sell another ((Y)es or (N)o)? ";
     cin>>YorN;
    }
    else
    {
     cout<<"You are out of money!"<<endl;
     break;
    }
   }
  }

  // This adds stuff for the player
  /////////////////////////////////
  void AddStuff()
  {
   Armies += Territory;
   Money += Territory;
   cout<<Name<<" now has "<<Armies
    <<" armies and "<<Money<<" money from ";
   cout<<Name<<"'s states."<<endl<<endl;
  }

 };

private:

 CPlayer *Rear;

public:

 CPlayer *Front;

 //Set the Front and rear to point to 0
 //////////////////////////////////////
 CCountries()
 {
  Front = 0; //make front null
  Rear = 0; //make rear null

  char Exit = 'N'; // Y or N value

  AddPlayer(Total);

  while(toupper(Exit) != 'Y')
  {
   Total++;
   AddPlayer(Total);
   cout<<"Are you the last player ((Y)es or (N)o)? ";
   cin>>Exit;
  }
 }

 //The destructor that deletes any nodes on the queue
 ////////////////////////////////////////////////////
 ~CCountries()
 {
  CPlayer *Current; //The current node to delete
  CPlayer *Next;  //The next node to delete

  Current = Front; //start Current in the front

  //Until the list is empty delete the nodes
  while(Current!=0)
  {
   Next = Current->Link; //setup the next node
   delete Current;   //delete the current node
   Current = Next;   //prepare for the next loop run
  }
 }

 // This will let the player attack
 //////////////////////////////////
 bool Attack()
 {
  char Exit = 'Y';
  CPlayer *Victim;
  char VictimName[15]; // This will hold the victim's name
  bool Flag;    // True or flase value
  bool DeathFlag = FALSE; // True or false value
  bool Win = FALSE;

  while (toupper(Exit) == 'Y')
  {
   Victim = Front;
   Flag = FALSE;

   cout<<"What Player do you want to attack? ";
   cin>>VictimName;

   if ( strcmp(VictimName,Front->Name) == 0)
   {
    cout<<"If you want to fight your self be my guest!"<<endl;
   }

   Flag = FALSE; // Start Flag at FALSE

   for(int Player = 0; Player < Total - 1; Player ++)
   {
    // Don't open a link = to 0.
    if (Victim->Link != 0) Victim = Victim->Link;
    else
    {
     Flag = FALSE;
     break;
    }

    if (strcmp(VictimName,Victim->Name) == 0)
    {
     Flag = TRUE;
     break;
    }

   }

   if (Flag == FALSE)
   {
    cout<<"No such player, Try again."<<endl;
    continue; // This will go skip the rest of the loop and start again at the top
   }

   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 = Front->Armies - 1 - (Victim->Armies * Victim->Technology / 5);
    VictimArmies = Victim->Armies - 1 - (Front->Armies * Front->Technology / 5);
    Front->Armies = AttackerArmies;
    Victim->Armies = VictimArmies;

    if(Victim->Armies < 1)
    {
     Win = Dead(Victim);
     End();
     DeathFlag = TRUE;

     if(Front->Armies > 1)
     {
      Front->Armies += AddArmies;
      AddArmies *= 2;
      cout<<Front->Name<<" you now have "<<Front->Armies<<" armies for your kill."
       <<endl;
      return (TRUE);
     }
     else
     {
      Win = Dead(Front);
      End();
      if(DeathFlag == FALSE)
      {
       Victim->Armies += AddArmies;
       AddArmies *= 2;
       cout<<Victim->Name<<" you now have "<<Victim->Armies<<" armies for your kill."
        <<endl;
      }
      DeathFlag = TRUE;
      return (FALSE);
     }

     DeathFlag = TRUE;
     if (Win == TRUE) return (FALSE);
    }
    else if(Front->Armies < 1)
    {
     Win = Dead(Front);
     End();
     if(DeathFlag == FALSE)
     {
      Victim->Armies += AddArmies;
      AddArmies *= 2;
      cout<<Victim->Name<<" you now have "<<Victim->Armies<<" armies for your kill."
       <<endl;
     }
     DeathFlag = TRUE;
     return (FALSE);
    }

    if(End() == TRUE) break;
    else if(DeathFlag == FALSE)
    {
     Victim->CountryLoss();
     Front->CountryLoss();
     cout<<Front->Name<<" now has "<<Front->Armies<<" armies."<<endl;
     cout<<Victim->Name<<" now has "<<Victim->Armies<<" armies."<<endl;
     cout<<Front->Name<<", Would you like to attack again ((Y)es or (N)o)? ";
     cin>>YorN;
    }
   }

   if(End() == FALSE)
   {
    cout<<"Would you like to attack another Player ((Y)es or (N)o)? ";
    cin>>Exit;
   }
   else break;
  }

  return (TRUE); // Flag success
 }

 //Inserts a Player at the rear
 /////////////////////////////
 void Enqueue(CPlayer Player)
 {
  CPlayer *Ptr;   //Make a Ptr for the new node
  Ptr = new CPlayer; // create a queuenode and point to it with Ptr

  *Ptr = Player;
  Ptr->Link = 0;   //start the pointer at 0
  Ptr->Previous = Rear; //point to the previous player

  //If the node isn't empty set the last link to point to the new node
  if (Front != 0)
   Rear->Link = Ptr;
  //else make the Front point to it.
  else
   Front = Ptr;
  //Make the rear point to the new node
  Rear = Ptr;
 }

 //Delete the first player and return the data
 /////////////////////////////////////////////
 CPlayer Dequeue()
 {
  CPlayer Player; //the return value
  CPlayer *Ptr; //Will point to the first node

  //If there are nodes delete the first one
  if (Front != 0)
  {
   Ptr = Front;  //Have the Pointer aim at the Front
   Player = *Ptr;  //Copy the player
   Front = Ptr->Link; //Make Front point to the next node in line
   delete Ptr;   //delete the node
   Front->Previous = 0; // set to 0
   if (Front==0)  //If the list is empty make the rear point to 0
    Rear = 0;
  }
  //else print an error
  else
   cout<<"Hey man, there aren't any Players here!"<<endl;

  return (Player); //Return the deleted Player
 }

 //return TRUE if the game is over
 ///////////////////////////////////
 bool End()
 {
  if(Rear == Front)
  {
   cout<<endl
    <<"\t"<<Front->Name<<" You are the Winner!!!!!"
    <<endl<<endl
    <<"Thanks for Playing and Good Bye."<<endl;
   exit(EXIT_SUCCESS); // end program
  }
  else return (FALSE);
 }

private:

 // This will Delete a Player
 ////////////////////////////
 bool Dead(CPlayer *Victim)
 {
  CPlayer *Current;

  cout<<Victim->Name<<" you are dead!"<<endl;

  // Check to make sure is is not the first entry
  if(Victim->Previous != 0)
  {
   Current = Victim->Previous;
   Current->Link = Victim->Link;
  }
  else // else change the rear
  {
   Front = Victim->Link;
  }

  // Check to make sure it is not the last entry
  if(Victim->Link != 0)
  {
   Current = Victim->Link;
   Current->Previous = Victim->Previous;
  }
  else // else change the Rear
  {
   Rear = Victim->Previous;
  }
 

  delete Victim;

  return (FALSE);
 }

 // This adds a player
 void AddPlayer(int Total)
 {
  CPlayer *Ptr;   //Make a Ptr for the new node
  Ptr = new CPlayer; // create a queuenode and point to it with Ptr
  Ptr->Armies = 5;
  Ptr->Money = 5;
  Ptr->Territory = 5;
  Ptr->Technology = 1;
  Ptr->UpgradeCost = 5;

  cout<<"Player "<<Total<<" What is your name? ";
  cin>>Ptr->Name;

  Ptr->Link = 0;   //start the pointer at 0

  //If the node isn't empty, set the last link to point to the new node
  if (Front != 0)
  {
   Ptr->Previous = Rear;
   Rear->Link = Ptr;
  }
  //else make the Front point to it.
  else
  {
   Ptr->Previous = 0;
   Front = Ptr;
  }
  //Make the rear point to the new node
  Rear = Ptr;
 }
 

};

#endif


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

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

void main()
{
 char Answer;
 bool EndGame = FALSE;

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

 CCountries Countries;

 for(bool Continue = TRUE; ; Countries.Enqueue( Countries.Dequeue()))
 {
  Answer = 'l';
  Continue = TRUE;

  Countries.Front->WriteName();
  cout<<" take your seat."<<endl;
  cout<<"You have "<<Countries.Front->ShowArmies()<<" armies."<<endl;

  while (tolower(Answer) != 'p' && Continue == TRUE)
  {
   cout<<"Would you like to (U)pgrade, (G)row, (S)hrink, (A)ttack or (P)ass? ";
   cin>>Answer;
   if ( tolower(Answer) == 'a')
   {
    Continue = Countries.Attack();
    if(Countries.End() == TRUE)
    {
     EndGame = TRUE;
     break;
    }
 

    if(Continue == TRUE)
    {
     cout<<"Would you like to (U)pgrade, (G)row, (S)hrink or (P)ass? ";
     cin>>Answer;
     if (tolower(Answer) == 'u')
     {
      Countries.Front->Upgrade();
      cout<<"Would you like to (G)row, (S)hrink or (P)ass? ";
      cin>>Answer;
      if(tolower(Answer) == 'g')
      {
       Countries.Front->Grow();
      }
      else if(tolower(Answer) == 's')
      {
       Countries.Front->Shrink();
      }
     }
     else if(tolower(Answer) == 'g')
     {
      Countries.Front->Grow();
      cout<<"Would you like to (U)pgrade or (P)ass? ";
      cin>>Answer;
      if(tolower(Answer) == 'u')
      {
       Countries.Front->Upgrade();
      }
     }
     else if(tolower(Answer) == 's')
     {
      Countries.Front->Shrink();
      cout<<"Would you like to (U)pgrade or (P)ass? ";
      cin>>Answer;
      if(tolower(Answer) == 'u')
      {
       Countries.Front->Upgrade();
      }
     }

     Answer = 'p';
    }
   }
   else if(tolower(Answer) == 'u')
   {
    Countries.Front->Upgrade();
    cout<<"Would you like to (G)row, (S)hrink or (P)ass? ";
    cin>>Answer;
    if(tolower(Answer) == 'g')
    {
     Countries.Front->Grow();
    }
    else if(tolower(Answer) == 's')
    {
     Countries.Front->Shrink();
    }

    Answer = 'p';
   }
   else if(tolower(Answer) == 'g')
   {
    Countries.Front->Grow();
    cout<<"Would you like to (U)pgrade or (P)ass? ";
    cin>>Answer;
    if(tolower(Answer) == 'u')
    {
     Countries.Front->Upgrade();
    }

    Answer = 'p';
   }
   else if(tolower(Answer) == 's')
   {
    Countries.Front->Shrink();
    cout<<"Would you like to (U)pgrade or (P)ass? ";
    cin>>Answer;
    if(tolower(Answer) == 'u')
    {
     Countries.Front->Upgrade();
    }
    Answer = 'p';
   }
   else if(tolower(Answer) == 'p')
   {
    Answer = 'p';
   }
   else
   {
    cout<<"Sorry, bad input . . . try again"<<endl;
   }
  }
  if (Countries.End() == TRUE) break;
  else Countries.Front->AddStuff();
 }
}

For the next chapter we are going to have a rubicks cube text game created by Joseph Russell.  That will be the last text game the tutorial covers.  After that we will dive head first into Windows and DirectX programming.  This will be a very slow process so don't be surprised is it takes awhile for other chapters to be posted.
 


PREVIOUS CHAPTER      HOME