ex7-16.cpp - Example 7-16 Polymorphism - Life

// File: ex7-16.cpp

#include <iostream>
#include <cstdlib>
using namespace std;

enum Bool { FALSE, TRUE};
enum LifeForm {VACANT, WEED, RABBIT, HAWK};

const int GridSize = 10;
const int Cycles = 10;
const int NumberLifeForms = 4;
const int HawkLifeExpectancy = 8;
const int HawkOvercrowdingLimit = 3;
const int RabbitLifeExpectancy = 3;

class Grid;

class LivingThing
{
  protected:
	 int x,y;
	 void AssessNeighborhood(const Grid& G, int sm[]);
  public:
	 LivingThing(int _x, int _y): x(_x), y(_y) {}
	 virtual LifeForm WhoAmI() = 0;
	 virtual LivingThing* next(const Grid& G) = 0;
};

class Grid {
  friend void LivingThing::AssessNeighborhood(const Grid& G, int sm[]);
  private:
	 LivingThing* cell[GridSize][GridSize];
  public:
	 Grid();
	~Grid() { if (cell[1][1]) release();}
	 void update(Grid&);
	 void release();
	 void print();
};

/* This function counts the number of each LivingThing thing in
	the neighborhood.  A neighborhood is a square and the 8
	adjacent squares on each side of it */
void LivingThing::AssessNeighborhood(const Grid& G, int count[])
{
  int i, j;
  count[VACANT] = count[WEED] = count[RABBIT] = count[HAWK] = 0;
  for (i = -1; i <= 1; ++i)
	 for (j = -1; j <= 1; ++j)
		count[G.cell[x+i][y+j] -> WhoAmI()]++;
  return;
}

class Vacant:public LivingThing
{
  public:
	 Vacant(int _x, int _y):LivingThing(_x,_y) {}
	 LifeForm WhoAmI() {return (VACANT);}
	 LivingThing* next(const Grid& G);
};

class Weed : public LivingThing
{
  public:
	 Weed(int _x, int _y): LivingThing(_x,_y){}
	 LifeForm WhoAmI() {return (WEED);}
	 LivingThing* next(const Grid& G);
};

class Rabbit : public LivingThing
{
  protected:
	 int age;
  public:
	 Rabbit(int x, int y, int a = 0) : LivingThing(x,y), age(a) {}
	 LifeForm WhoAmI() { return (RABBIT); }
	 LivingThing* next(const Grid& G);
};

class Hawk : public LivingThing
{
  protected:
	 int age;
  public:
	 Hawk(int x, int y, int a = 0): LivingThing(x,y), age(a){}
	 LifeForm WhoAmI() {return (HAWK);}
	 LivingThing* next(const Grid& G);
};

// This function determines what will be in an Vacant square in the next cycle
LivingThing* Vacant::next(const Grid& G)
{
  int count[NumberLifeForms];
  AssessNeighborhood(G,count);

// If there is more than one Rabbit in the neighborhood, a new Rabbit
//	is born.
  if (count[RABBIT] > 1)   return (new Rabbit(x,y));

// otherwise, if there is more than one Hawk, a Hawk will be born
  else if (count[HAWK] > 1) return (new Hawk(x, y));

// otherwise, if there is Weed in the neighborhood, Weed will grow
  else if (count[WEED])   return (new Weed(x, y));

// otherwise the square will remain Vacant
  else return (new Vacant(x, y));
}

// if there is more Weeds than Rabbits, then new Weed will grow,
// otherwise Vacant
LivingThing* Weed::next(const Grid& G)
{
  int count[NumberLifeForms];
  AssessNeighborhood(G, count);
  if (count[WEED] > count[RABBIT])	return (new Weed(x, y));
  else return (new Vacant(x, y));
}

/* The Rabbit dies if:
	there's more Hawks in the neighborhood than Rabbits
	not enough to eat
	or if it's too old
	otherwise a new Rabbit is born */
LivingThing* Rabbit::next(const Grid& G)
{
  int count[NumberLifeForms];
  AssessNeighborhood(G, count);
  if (count[HAWK] >= count[RABBIT] ) return (new Vacant(x, y));
  else if (count[RABBIT] > count[WEED]) return (new Vacant(x, y));
  else if (age > RabbitLifeExpectancy) return (new Vacant(x, y));
  else return (new Rabbit(x,y, age + 1));
}

// Hawk die of overcrowding, starvation, or old age
LivingThing* Hawk::next(const Grid& G)
{
  int count[NumberLifeForms];
  AssessNeighborhood(G, count);
  if (count[HAWK] > HawkOvercrowdingLimit) return (new Vacant(x, y));
  else if (count[RABBIT] < 1) return (new Vacant(x,y));
  else if (age > HawkLifeExpectancy) return (new Vacant (x, y));
  else return (new Hawk(x, y, age + 1));
}

Grid::Grid()
{
  LifeForm creature;
  int i, j;
  for (i = 0; i < GridSize; i++)
	 for (j = 0; j < GridSize; j++)
	 {
		if (i == 0 || i == GridSize - 1 || j ==0 || j == GridSize - 1)
		  creature = VACANT;
		else
		  creature = LifeForm(rand() % NumberLifeForms);
		switch (creature)
		{
		  case HAWK:    cell[i][j] = new Hawk(i,j);      break;
		  case RABBIT:  cell[i][j] = new Rabbit(i,j);   break;
		  case WEED:    cell[i][j] = new Weed(i,j);    break;
		  case VACANT:  cell[i][j] = new Vacant(i,j);
		}
	 }
}

void Grid::release()
{
  int i, j;
  for (i = 1; i < GridSize - 1; ++i)
    for (j = 1; j < GridSize - 1; ++j) delete cell[i][j];
  cell[1][1] = 0;
}

void Grid::update(Grid& old)
{
  int i, j;
  for (i = 1; i < GridSize - 1; ++i)
	 for (j = 1; j < GridSize - 1; ++j)
		cell[i][j] = old.cell[i][j] -> next(old);
}

void Grid::print()
{
  LifeForm creature;
  int i, j;
  for (i = 1; i < GridSize - 1; i++)
  {
	 for (j = 1; j < GridSize - 1; j++)
	 {
		creature = cell[i][j]->WhoAmI();
		switch (creature)
		{
		  case HAWK:      cout << "H"; break;
		  case RABBIT:   cout << "R"; break;
		  case WEED:    cout << "W"; break;
		  case VACANT:    cout << "0";
		}
	 }
	 cout << endl;
  }
  cout << endl;
  return;
}

int main(void)
{
  Grid G1, G2;
  G1.print();

  for (int i = 1; i <= Cycles; i++)
  {
	 cout << "Cycle " << i << endl;
	 if (i % 2)
	 {
		G2.update(G1);
		G2.print();
		G1.release();
	 }
	 else
	 {
		G1.update(G2);
		G1.print();
		G2.release();
	 }
  }
  return 0;
}



CIS27: Programming in C++    Instructor: Joe Bentley