|
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