//grammar_functions.cpp
//by John Ahlschwede
//defines member functions for node classes

#include "grammar.h"

//##################################################
//    NODE FUNCTIONS
//##################################################

node::node()
{
	return;
}


node::~node()
{
	return;
}

int node::exe(int game[14])
{
	return 0;
}

void node::print()
{
	cout << "NULL";
}

void node::grow(int)
{
	return;
}


node* node::make_new(int tilt)
{

	int key = rand() % 100;
	if(key + tilt < 20)
		return new if_lessthan_do_else();
	if(key + tilt < 40)
		return new subtraction();
	if(key + tilt < 60)
		return new addition();
	if(key + tilt < 80)
		return new value_at();
	return new terminal();

}

node *node::copyNode()
{
	return NULL;
}

node *node::findNode(int depth2dig)
{
	return this;
}

void node::addTree(node *tree)
{
	delete tree;
}


int node::countSize()
{
	return 0;
}

//##################################################
//    IF_LESSTHAN_DO_ELSE FUNCTIONS
//##################################################




if_lessthan_do_else::if_lessthan_do_else()
{
	operand1 = NULL;
	operand2 = NULL;
	then_do = NULL;
	else_do = NULL;
}

if_lessthan_do_else::~if_lessthan_do_else()
{
	if(operand1 != NULL)
		delete operand1;
	if(operand2 != NULL)
		delete operand2;
	if(then_do != NULL)
		delete then_do;
	if(else_do != NULL)
		delete else_do;
}

int if_lessthan_do_else::exe(int game[14])
{
	int one, two;
	one = operand1->exe(game);
	two = operand2->exe(game);
	if(one < two)
		return then_do->exe(game);
	return else_do->exe(game);
}


void if_lessthan_do_else::print()
{
	cout << "(if ";
	operand1->print();
	cout << " < ";
	operand2->print();
	cout << " do ";
	then_do->print();
	cout << " else do ";
	else_do->print();
	cout << ")";
}

void if_lessthan_do_else::grow(int depth)
{
	depth += chunk;

	if(operand1 != NULL)
		delete operand1;
	if(operand2 != NULL)
		delete operand2;
	if(then_do != NULL)
		delete then_do;
	if(else_do != NULL)
		delete else_do;

	operand1 = make_new(depth); 
	operand2 = make_new(depth); 	
	then_do = make_new(depth); 
	else_do = make_new(depth);
	
	operand1->grow(depth);
	operand2->grow(depth);
	then_do->grow(depth);
	else_do->grow(depth);

}


node *if_lessthan_do_else::copyNode()
{
	if_lessthan_do_else *newGuy;
	newGuy = new if_lessthan_do_else;
	newGuy->setOperand1(operand1->copyNode());
	newGuy->setOperand2(operand2->copyNode());
	newGuy->setThen_do(then_do->copyNode());
	newGuy->setElse_do(else_do->copyNode());
	return newGuy;
}


node *if_lessthan_do_else::findNode(int depth2dig)
{

	node *temp = NULL;

	if(depth2dig < 1)
		return this;
	
	else
	{
		int chosen = rand() % 4;
		if(chosen == 0)
		{
			temp = operand1->findNode(depth2dig - 1);
			if(temp != NULL)
				return temp;
			return this;
		}
		if(chosen == 1)
		{
			temp = operand2->findNode(depth2dig - 1);
			if(temp != NULL)
				return  temp;
			return this;
		}
		if(chosen == 2)
		{
			temp = then_do->findNode(depth2dig - 1);
			if(temp != NULL)
				return temp;
			return this;

		}
		temp = else_do->findNode(depth2dig - 1);
		if(temp != NULL)
			return temp;
		return this;		
	}
}

void if_lessthan_do_else::addTree(node *tree)
{
	int chosen = rand() % 4;
	if(chosen == 0)
	{
		delete operand1;
		operand1=tree;
		return;
	}
	if(chosen == 1)
	{
		delete operand2;
		operand2=tree;
		return;
	}	
	if(chosen == 2)
	{
		delete then_do;
		then_do=tree;
		return;
	}	
	delete else_do;
	else_do = tree;
	return;
	
}


int if_lessthan_do_else::countSize()
{
	return operand1->countSize() + operand2->countSize() 
		+ then_do->countSize() + else_do->countSize() + 1;
}

//##################################################
//    ADDITION FUNCTIONS
//##################################################






addition::addition()
{
	operand1 = NULL;
	operand2 = NULL;
}

addition::~addition()
{
	if(operand1 != NULL)
		delete operand1;
	if(operand2 != NULL)
		delete operand2;
}


int addition::exe(int game[14])
{
	return (operand1->exe(game)) + (operand2->exe(game));
}


void addition::print()
{
	cout << "(";
	operand1->print();
	cout << " + ";
	operand2->print();
	cout << ")";
	
}

void addition::grow(int depth)
{
	depth += chunk;

	if(operand1 != NULL)
		delete operand1;
	if(operand2 != NULL)
		delete operand2;

	
	operand1 = make_new(depth); 
	operand2 = make_new(depth); 	
	
	operand1->grow(depth);
	operand2->grow(depth);
}



node *addition::copyNode()
{
	addition *newGuy;
	newGuy = new addition;
	newGuy->setOperand1(operand1->copyNode());
	newGuy->setOperand2(operand2->copyNode());
	return newGuy;
}

node *addition::findNode(int depth2dig)
{
	node *temp = NULL;

	if(depth2dig < 1)
		return this;
	
	else
	{
		int chosen = rand() % 2;
		if(chosen == 0)
		{
			temp = operand1->findNode(depth2dig - 1);
			if(temp != NULL)
				return temp;
			return this;
		}
		temp = operand2->findNode(depth2dig - 1);
		if(temp != NULL)
			return temp;
		return this;		
	}
}





void addition::addTree(node *tree)
{
	int chosen = rand() % 2;
	if(chosen == 0)
	{
		delete operand1;
		operand1=tree;
		return;
	}
	
	delete operand2;
	operand2=tree;
	return;
	
}


int addition::countSize()
{
	return operand1->countSize() + operand2->countSize() + 1;
}
//##################################################
//    SUBTRACTION FUNCTIONS
//##################################################






subtraction::subtraction()
{
	operand1 = NULL;
	operand2 = NULL;
}


subtraction::~subtraction()
{
	if(operand1 != NULL)
		delete operand1;
	if(operand2 != NULL)
		delete operand2;
}

int subtraction::exe(int game[14])
{
	return (operand1->exe(game)) - (operand2->exe(game));
}


void subtraction::print()
{
	cout << "(";
	operand1->print();
	cout << " - ";
	operand2->print();
	cout << ")";
	
}

void subtraction::grow(int depth)
{
	depth += chunk;

	if(operand1 != NULL)
		delete operand1;
	if(operand2 != NULL)
		delete operand2;
	
	operand1 = make_new(depth); 
	operand2 = make_new(depth); 	
	
	operand1->grow(depth);
	operand2->grow(depth);
}



node *subtraction::copyNode()
{
	subtraction *newGuy;
	newGuy = new subtraction;
	newGuy->setOperand1(operand1->copyNode());
	newGuy->setOperand2(operand2->copyNode());
	return newGuy;
}


node *subtraction::findNode(int depth2dig)
{
	node *temp = NULL;

	if(depth2dig < 1)
		return this;
	
	else
	{
		int chosen = rand() % 2;
		if(chosen == 0)
		{
			temp = operand1->findNode(depth2dig - 1);
			if(temp != NULL)
				return temp;
			return this;
		}
		temp = operand2->findNode(depth2dig - 1);
		if(temp != NULL)
			return temp;
		return this;		
	}
}

void subtraction::addTree(node *tree)
{
	int chosen = rand() % 2;
	if(chosen == 0)
	{
		delete operand1;
		operand1=tree;
		return;
	}
	
	delete operand2;
	operand2=tree;
	return;
	
}


int subtraction::countSize()
{
	return operand1->countSize() + operand2->countSize() + 1;
}

//##################################################
//    VALUE_AT FUNCTIONS
//##################################################






value_at::value_at()
{
	operand1 = NULL;
}


value_at::~value_at()
{
	if(operand1 != NULL)
		delete operand1;
}

int value_at::exe(int game[14])
{
	int temp = operand1->exe(game);


	if((temp < 0) && ((temp % 14) != 0) ) 
		return game[(14 + (temp % 14))];

	return game[temp % 14];

}


void value_at::print()
{
	cout << "(value at [";
	operand1->print();
	cout << "])";
}

void value_at::grow(int depth)
{
	depth += chunk;

	if(operand1 != NULL)
		delete operand1;
	
	operand1 = make_new(depth); 
		
	operand1->grow(depth);
}




node *value_at::copyNode()
{
	value_at *newGuy;
	newGuy = new value_at;
	newGuy->setOperand1(operand1->copyNode());
	return newGuy;
}



node *value_at::findNode(int depth2dig)
{

	node *temp = NULL;
	if(depth2dig < 1)
		return this;
	else
	{
		temp = operand1->findNode(depth2dig - 1);
		if(temp != NULL)
			return temp;
		return this;
	}
}


void value_at::addTree(node *tree)
{
	delete operand1;
	operand1=tree;
	return;
	
}



int value_at::countSize()
{
	return operand1->countSize() + 1;
}
//##################################################
//    TERMINAL FUNCTIONS
//##################################################






terminal::terminal()
{

	value = rand() % 14;
}



int terminal::exe(int game[14])
{
	return value;

}


void terminal::print()
{
	cout << "(" << value << ")";
}

void terminal::grow(int depth)
{
	return;
}


node *terminal::copyNode()
{
	terminal *newGuy;
	newGuy = new terminal;
	newGuy->setValue(value);
	return newGuy;
}


node *terminal::findNode(int depth2dig)
{
	return NULL;
}

void terminal::addTree(node *tree)
{
	delete tree;
	return;
	
}


int terminal::countSize()
{
	return 1;
}