#include "stdafx.h"
#include <iostream>
#include <iomanip>
using namespace std;
#include <fstream>
#include <time.h>
#include <cstdlib>
#include <ctime>
#include <string>
#include <string.h>
void Timestep (int a);
const int DimX =200;
const int DimY =200;//These variables set the size of the array
ifstream paramfile;
ofstream evodata;
int Seedval = 5;
int Initvalp = 50;
int Initvalbig = 35;
int Initvaldin =7;
int plantAge = 4;
int Hungerbig = 2;
int Hungerdin = 4;
int agebig = 24 ;
int agedin = 36;
int gestbig = 2;
int gestdin = 4;
int Runlength = 1000;
int Defense = 30;
string outFileName = "Results.csv";

void ReadParams ()
{
	string token;
	string Rootname;
	string line;
	getline (cin, Rootname);
	paramfile.open (Rootname + ".txt");
	if (!paramfile)
	{
		cerr << "Could not open input file " << Rootname << ".txt" << endl;
		cerr << "Press Enter to continue." << endl;
		getline (cin, line);
		exit (1);
	}
	evodata.open (Rootname +".csv");
	if (!evodata) 
	{
		cerr << "Could not open output file " << Rootname << ".csv" << endl;
		cerr << "Press Enter to continue." << endl;
		getline (cin, line);
		exit (1);
	}
	while (paramfile >> token)
	{
		if (!token.compare ("Seedval"))
			paramfile >> Seedval;
		else if (!token.compare ("Initvalp"))
			paramfile >> Initvalp;
		else if (!token.compare ("Initvalbig"))
			paramfile >> Initvalbig;
		else if (!token.compare ("Initvaldin"))
			paramfile >> Initvaldin;
		else if (!token.compare ("plantAge"))
			paramfile >> plantAge;
		else if (!token.compare ("Hungerbig"))
			paramfile >> Hungerbig;
		else if (!token.compare ("Hungerdin"))
			paramfile >> Hungerdin;
		else if (!token.compare ("agebig"))
			paramfile >> agebig;
		else if (!token.compare ("agedin"))
			paramfile >> agedin;
		else if (!token.compare ("gestbig"))
			paramfile >> gestbig;
		else if (!token.compare ("gestdin"))
			paramfile >> gestdin;
		else if (!token.compare ("Runlength"))
			paramfile >> Runlength;
		else if (!token.compare ("Defense"))
			paramfile >> Defense;

		else {
			cerr << "Error: Unknown Token: " << token << endl;
			cerr << "Press Enter to continue." << endl;
			getline (cin, line);
			exit (1);
		}
	}
}

class plant
{
public:
	bool Alive;
	int maturity;
	plant()
	{
		maturity = 0;
		Alive = false;
	}

	void SetTraits ()
	{	
		Alive = true;
	}
};

class primaryConsumer 
{
private:
	static int count;
public:
	int age;
	bool movement;
	bool Mother;
	int Nest;
	bool Male;
	int ID;
	int hunger;
	primaryConsumer()
	{
		Mother = false;
		age = 0;
		hunger = 0;
		ID = count;
		count++;
		
	}

	void setTraits ()
	{

		int XYchrom = rand()%(100)+1;
		if (XYchrom < 50)
			Male = true;
		else
			Male = false;	
	}
};

int primaryConsumer::count = 0;
class predator
{
private:
	static int count;
public:
	int age;
	bool movement;
	bool Mother;
	int Nest;
	bool Male;
	int ID;
	int hunger;
	predator ()
	{
		Mother = false;
		age = 0;
		hunger = 0;
		ID = count;
		count++;
	}

	void setTraits ()
	{
		int XYchrom = rand()%(100)+1;
		if (XYchrom < 50)
			Male = true;
		else
			Male = false;
	}
};

int predator::count = 0;

class Ecosystem 
{
public:
	primaryConsumer *SquatchLand [DimY][DimX];
	plant plantland [DimY][DimX];
	predator *jpark [DimY][DimX];
	int Totalarray [DimY][DimX];
	int Transfer[DimY][DimX];
	int Numplants;
	int Numsas;
	int Numdin;

	Ecosystem ()
	{
		Numplants = 0;
		Numsas = 0;
		Numdin = 0;
		for(int i = 0; i<DimY;i++)
		{
			for(int j = 0; j<DimX;j++)
			{
				SquatchLand [i][j] = NULL;
				jpark [i][j] = NULL;
			}
		}
				
	}
	void SquatchlifeCheck ()
	{
		for(int row=0; row < DimY;row++)
		{
			for(int col=0; col <DimX; col++)
			{
				if(SquatchLand[row][col]!=NULL)
				{
					SquatchLand[row][col]->movement = true;
					SquatchLand[row][col]->age++;
					if(SquatchLand[row][col]->Mother == true)
					{
						SquatchLand[row][col]->Nest++;
							if (SquatchLand [row][col]->Nest >=gestbig)
							BBirth(row, col);
					}
					if (!SquatchLand[row][col]->Male)
						BBreed(row,col);
					if(SquatchLand [row][col]->age > agebig)
					{
						delete SquatchLand[row][col];
						SquatchLand[row][col] = NULL;
					}
					else if(SquatchLand[row][col]->hunger >= Hungerbig)
					{
						delete SquatchLand[row][col];
						SquatchLand[row][col] = NULL;
					}
				}
			}
		}
	}
	void DinoLifeCheck()
	{
		for(int row=0; row < DimY;row++)
		{
			for(int col=0; col <DimX; col++)
			{
				if(jpark[row][col]!=NULL)
				{
					jpark[row][col]->age++;
					jpark[row][col] ->movement =true;
					if(jpark[row][col]->Mother == true)
					{
						jpark[row][col]->Nest++;
							if (jpark [row][col]->Nest >=gestdin)
							DBirth(row, col);
					}
					if (!jpark[row][col]->Male)
						DBreed(row,col);
					if (jpark[row][col]->age > agedin)
					{
						delete jpark[row][col];
						jpark[row][col] = NULL;
					}
					else if(jpark[row][col]->hunger >= Hungerdin)
					{
						delete jpark[row][col];
						jpark[row][col] = NULL;
					}
				}
			}
		}
	}
	void plantRegen ()
	{
		for(int row =0; row<DimY;row++)
		{
			for(int col = 0; col<DimX;col ++)
			{
				if(!plantland[row][col].Alive && !SquatchLand[row][col])
				{
					plantland[row][col].maturity ++; 
					if(plantland[row][col].maturity ==plantAge)
						plantland[row][col].SetTraits();
				}
			}
		}
	}
	void Bigmeal ()
	{
		for(int row =0; row<DimY;row++)
		{
			for(int col = 0; col<DimX;col ++)
			{
				if (SquatchLand[row][col] && SquatchLand[row][col]->movement)
				{
					struct {
						int row, col;
					} possibleSquare [48];
					int possibleSquares = 0;
					bool canMove = SquatchLand[row][col]->movement;
					int absRow, absCol;
					for(int Relrow = -3; Relrow <= 3 && canMove; Relrow++)
					{
						absRow = Relrow + row;
						if( absRow >= 0 && absRow < DimY)
						{
							for (int Relcol = -3; Relcol <= 3 &&
								canMove; Relcol++)
							{
								absCol = Relcol + col;
								if(absCol >= 0 && absCol < DimX)
								{
									if(plantland[absRow][absCol].Alive && 
										!jpark[absRow][absCol])
									{
										possibleSquare[possibleSquares].row =
											absRow;
										possibleSquare[possibleSquares].col =
											absCol;
										possibleSquares++;
									}
								}
							}
						}
					}
					if (possibleSquares>0)
					{
						int decideSquare = rand()%possibleSquares;
						absRow = possibleSquare[decideSquare].row;
						absCol = possibleSquare[decideSquare].col;
						SquatchLand[absRow][absCol] = SquatchLand[row][col];
						SquatchLand[row][col] = NULL;
						plantland[absRow][absCol].Alive = false;
						plantland[absRow][absCol].maturity = 0;
						SquatchLand[absRow][absCol]->movement = false;
						SquatchLand[absRow][absCol]->hunger = 0;
					}
					else 
					{
						SquatchLand[row][col]->hunger++; 
					}
				}
			}
		}
	}
	void Dinomeal ()
	{
		for(int row =0; row<DimY;row++)
		{
			for(int col = 0; col<DimX;col ++)
			{
				int defense = rand()%100 + 1;
				if (jpark[row][col]!= NULL && jpark[row][col]->movement)
				{
					struct {
						int row, col;
					} possibleSquare [48];
					struct{
						int row, col;
					} randSquare [48];
					int randomSquares = 0;
					int possibleSquares = 0;
					bool canMove = jpark[row][col]->movement;
					int absRow, absCol;
					for(int Relrow = -3; Relrow <= 3 && canMove; Relrow++)
					{
						absRow = Relrow + row;
						if( absRow >= 0 && absRow < DimY)
						{
							for (int Relcol = -3; Relcol <= 3 &&
								canMove; Relcol++)
							{
								absCol = Relcol + col;
								if(absCol >= 0 && absCol < DimX)
								{
									if (jpark[absRow][absCol] == NULL)
									{
										if(!SquatchLand[absRow][absCol])
										{
											randSquare[randomSquares].row = absRow;
											randSquare[randomSquares].col = absCol;
											randomSquares++;
										}
										if (SquatchLand[absRow][absCol])
										{
											possibleSquare[possibleSquares].row =
												absRow;
											possibleSquare[possibleSquares].col = 
												absCol;
											possibleSquares++;
										}
									}
								}
							}
						}
					}
					if (possibleSquares>0 && defense>Defense)
					{
						int decideSquare = rand()%possibleSquares;
						absRow = possibleSquare[decideSquare].row;
						absCol = possibleSquare[decideSquare].col;
						delete SquatchLand[absRow][absCol];
						SquatchLand[absRow][absCol] = NULL;
						jpark[absRow][absCol] = jpark[row][col];
						jpark[row][col] = NULL;
						jpark[absRow][absCol]->movement = false;
						jpark[absRow][absCol]->hunger = 0;
					}
					else if(randomSquares>0)
					{
						int RandMove =rand()%randomSquares;
						absRow = randSquare[RandMove].row;
						absCol = randSquare[RandMove].col;
						jpark[absRow][absCol] = jpark[row][col];
						jpark[row][col] = NULL;
						jpark[absRow][absCol]-> movement = false;
						jpark[absRow][absCol]-> hunger ++;
					}
				}
			}
		}
	}
	void BBreed(int row, int col)
	{
		int absRow, absCol;
		for(int Relrow = -3; Relrow <= 3 && 
			!SquatchLand[row][col]->Mother ; Relrow++)
		{
			absRow = Relrow + row;
			if( absRow >= 0 && absRow < DimY)
			{
				for (int Relcol = -3; Relcol <= 3 && 
					!SquatchLand[row][col]->Mother; Relcol++)
				{
					absCol = Relcol + col;
					if(absCol >= 0 && absCol < DimX)
					{
						if ( SquatchLand[absRow][absCol] &&
							SquatchLand[absRow][absCol]->Male)
						{
							SquatchLand[row][col]->Mother = true;
							SquatchLand[row][col]->Nest = 0;

						}
					}
				}
			}
		}
	}
		void DBreed(int row, int col)
	{
		int absRow, absCol;
		for(int Relrow = -4; Relrow <= 4 &&!jpark[row][col]->Mother ; Relrow++)
		{
			absRow = Relrow + row;
			if( absRow >= 0 && absRow < DimY)
			{
				for (int Relcol = -4; Relcol <= 4 && 
					!jpark[row][col]->Mother; Relcol++)
				{
					absCol = Relcol + col;
					if(absCol >= 0 && absCol < DimX)
					{
						if ( jpark[absRow][absCol] && 
							jpark[absRow][absCol]->Male == true)
						{
							jpark[row][col]->Mother = true;
							jpark[row][col]->Nest = 0;

						}
					}
				}
			}
		}
	}
	void BBirth (int row, int col)
	{

		if (SquatchLand[row][col]!= NULL && SquatchLand[row][col]->movement)
		{
			struct {
				int row, col;
			} possibleSquare [8];
			int possibleSquares = 0;
			int absRow, absCol;
			for(int Relrow = -1; Relrow <= 1 ; Relrow++)
			{
				absRow = Relrow + row;
				if( absRow >= 0 && absRow < DimY)
				{
					for (int Relcol = -1; Relcol <= 1; Relcol++)
					{
						absCol = Relcol + col;
						if(absCol >= 0 && absCol < DimX)
						{
							if (SquatchLand[absRow][absCol] == NULL && 
								jpark[absRow][absCol] == NULL)
							{
								possibleSquare[possibleSquares].row = absRow;
								possibleSquare[possibleSquares].col = absCol;
								possibleSquares++;
							}
						}
					}
				}
			}
			if (possibleSquares>0)
			{
				int decideLeave = rand()%possibleSquares;
				absRow = possibleSquare[decideLeave].row;
				absCol = possibleSquare[decideLeave].col;
				SquatchLand[absRow][absCol] = new primaryConsumer;
				SquatchLand[absRow][absCol]->setTraits();
				plantland[absRow][absCol].Alive = false;
				plantland[absRow][absCol].maturity = 0;
				SquatchLand[row][col]->Nest =0;
			}
		}
	}
		void DBirth (int row, int col)
	{
		for(int i = 0;  i<2; i++)
		{
			if (jpark[row][col]!= NULL && jpark[row][col]->movement)
			{
				struct {
					int row, col;
				} possibleSquare [8];
				int possibleSquares = 0;
				int absRow, absCol;
				for(int Relrow = -1; Relrow <= 1 ; Relrow++)
				{
					absRow = Relrow + row;
					if( absRow >= 0 && absRow < DimY)
					{
						for (int Relcol = -1; Relcol <= 1; Relcol++)
						{
							absCol = Relcol + col;
							if(absCol >= 0 && absCol < DimX)
							{
								if (jpark[absRow][absCol] == NULL &&
									jpark[absRow][absCol] == NULL)
								{
									possibleSquare[possibleSquares].row = absRow;
									possibleSquare[possibleSquares].col = absCol;
									possibleSquares++;
								}
							}
						}
					}
				}
				if (possibleSquares>0)
				{
					int decideLeave = rand()%possibleSquares;
					absRow = possibleSquare[decideLeave].row;
					absCol = possibleSquare[decideLeave].col;
					jpark[absRow][absCol] = new predator;
					jpark[absRow][absCol]->setTraits();
					delete SquatchLand[absRow][absCol];
					SquatchLand[absRow][absCol] = NULL;
					jpark[row][col]->Nest =0;
				}
			}
		}
	}
	void Initialize ()
	{
		for (int row = 0;row < DimY; row ++)
		{
			for (int col = 0; col<DimX;col ++)
			{
				int Growth = rand () % plantAge;
				int decision = rand () % (100)  + 1;
				if (decision <=Initvalp ) 
				{
					plantland [row][col].SetTraits();
					Totalarray [row][col] = 1;
					plantland [row][col].maturity = plantAge;
					Numplants ++;
				}
				else 
					plantland [row][col].maturity = Growth;
			}
		//	cout<<endl;
		}	
	//	cout<< "There are "<<Numplants<<" plants in this ecosystem."<<endl;
		for (int row = 0; row<DimY; row++)
		{
			for(int col = 0; col <DimX; col++)
			{
				int decision2 = rand () % (100)  + 1;
				if (decision2 <=Initvalbig && plantland[row][col].Alive == false)
				{
					primaryConsumer *Bigfoot = new primaryConsumer;
					Bigfoot->setTraits();	
					SquatchLand [row][col] = Bigfoot ;
					plantland[row][col].maturity =0;
					Numsas ++;
				}
			}
		}	
//		cout<<endl<<"There are "<<Numsas<<" Bigfoots in the ecosystem."<<endl;
		for (int row = 0; row<DimY;row++)
		{
			for (int col = 0; col<DimX; col++)
			{
				int decision3 = rand () % (100)  + 1;
				if (decision3 <= Initvaldin && SquatchLand[row][col] == NULL)
				{
					predator *Trex = new predator;
					Trex->setTraits();
					jpark[row][col] = Trex;
					Numdin ++;
				}
			}
		}
//		cout<<endl<<"There are "<<Numdin<<" Dinosaurs in this ecosystem."
//			<<endl<<endl;
		void PrintGrid();
	}
	void PrintGrid()
	{
		cout<<setfill('0');
		for(int i=0;i<DimY;i++)
		{
			for(int j=0;j<DimX;j++)
			{
				if(plantland[i][j].Alive == true&&jpark[i][j]==NULL)
				{
					cout<<"|P";
				}
				else if(SquatchLand[i][j]!=NULL)
				{
					cout<<"|B";
				}
				else if(jpark[i][j]!=NULL&&plantland[i][j].Alive == false)
				{
					cout<<"|D";
				}
				else if (jpark[i][j]!=NULL &&plantland[i][j].Alive == true)
				{
					cout<<"|H";
				}
				else
				{
					cout<< "| ";
				}
			}

			cout<<endl;
		}
	}
void Counter (int age)
{
	int Dincount=0;
	int Squatchcount = 0;
	int plantCount = 0;
	for(int row = 0; row<DimY;row++)
	{
		for(int col = 0; col<DimX;col++)
		{
			if(SquatchLand[row][col])
				Squatchcount++;
			if(jpark[row][col] )
				Dincount ++;
			if(plantland[row][col].maturity == plantAge)
			{
				plantCount ++;
			}
		}
	}
//	cout<<"there are: "<<plantCount<<" alive plants"<<endl;
//	cout<<"there are: "<<Squatchcount<<" Bigfoots"<<endl;
//	cout<<"there are: "<<Dincount<< " Dinosaurs"<<endl;
	evodata<<age<<","<<plantCount<<","<<Squatchcount<<","<<Dincount<<endl;
}

void natDisast1()
{
	for(int row = 0; row<DimY;row++)
	{
		for(int col = 0; col<DimX;col++)
		{
			if (row>(DimY/2))
			{
				if (SquatchLand[row][col])
				{
					delete SquatchLand[row][col];
					SquatchLand[row][col] =NULL;
				}
				else if (jpark[row][col])
				{
					delete jpark[row][col];
					jpark[row][col] = NULL;
				}
				else
					plantland[row][col].maturity = 0;
			}
		}
	}
}
void Deforestation()
{
	for(int row = 0; row<DimY;row++)
	{
		for(int col = 0; col<DimX;col++)
		{
			if (row >= DimY/2 && col< DimX/2) 
			{
				plantland[row][col].maturity = 0;
				plantland[row][col].Alive =false;
			}
		}
	}
}
private:

};

int main()
{
	Ecosystem Nature;
	ReadParams();
	if(Seedval == 0)
	{
		srand((unsigned int) time(0));
	}
	else
	{
		srand((unsigned int) (Seedval));
	}
	Nature.Initialize();
//	Nature.PrintGrid();
	string input;
	for (int iter = 0; iter <Runlength; iter++)
	{
		Nature.SquatchlifeCheck();
		Nature.DinoLifeCheck();
		Nature.Bigmeal();
		Nature.plantRegen();
		Nature.Dinomeal();
//		if (iter%100 == 0)
	//	{
		//	Nature.PrintGrid();
		//	getline(cin, input);
	//	}
	//	if (iter == 500)
	//		Nature.Deforestation();
		Nature.Counter(iter);
	//	cout<<" The age of the Ecosystem is: "<<1 + iter<<endl;
	}
	return 0;
}