#include "robot.hpp"


//------------------------ ROBOT Module -------------------------//
//						  v 08 . 03 .  2007						 //
//																 //
//								MT								 //
//---------------------------------------------------------------//



/*
300$ - raw/month
500$ - prod/month
1000$ - fabric/month
*/

/*
.tell <nick> <message>
say <message>


prod <n>	(2000$ by fabric, 2000$ * 2 - auto)
sell <n> <price>
buy <n> <price>

build	(2500$ + 2500$ / 5 month)
abuild	(5000$ + 5000$ / 7 month)
upgrade	(3500$ + 3500$ / 9 month)

*/

#define PRICE_PLANT 2500
#define PRICE_AUTO 5000
#define PRICE_UPGRADE 3500

#define PRICE_KEEPING_RAW 300
#define PRICE_KEEPING_PROD 500
#define PRICE_KEEPING_PLANT 1000
#define PRICE_KEEPING_AUTO 1500


	// --- helper routines ---//
	double NotLess0(double a);
	int IsPlayerPlaying(CGamer &p);
	void N_F(double sigma, double a, spoint *g, int n, int inverse = 0);


// --- Constructor ROBOT --- //
CRobot :: CRobot (CData *d, CSocket *s)
{
	Data = d;
	Socket = s;
	Data -> win = 0;
		
	turn_ = 0;
	make_ = 0;
};


void CRobot :: Pass()
{
	int raw_price = Data->market.min_raw_price;
	int prod_price = Data->market.max_prod_price;

	int prod_n = Data->you.raw;
	int sell_n = Data->you.prod;
	int buy_n = Data->you.fabrics;
	
	double scale = 0;

// --- Fair analyZe ---

	// --- Prod to produce -------------------------------------------------
	prod_n = GetPlayerOptimalProdN(Data->you);
	
	// --- Buy raw N -------------------------------------------------------
	buy_n = GetPlayerOptimalBuyN(Data->you, prod_n);
	
	// --- Buy raw price ---------------------------------------------------
	scale = (double) GetAllPlayers_Producing() / Data->market.raw;
		if (scale > 1) raw_price = (int) (raw_price * scale);
	
	// --- Sell prod price -------------------------------------------------
		int render = 0;
		int tmp, tmp_i;
		for (int i = 1; i<Data->market.max_prod_price; i++)
			if ( (tmp = GetClearProfit(Data->you, i)) > render) 
			{
				render = tmp;
				tmp_i = i;
			}
	
		prod_price = tmp_i;


	// --- Upgrade ---------------------------------------------------------
	if (make_ > 0)	turn_ --;
	if (turn_ == 0) make_ = 0;
		
	if (make_ == 0)
		if (Data->you.fabrics > 0)	
			if (Data->you.money > 25000)
				{
					make_ = 1;
					turn_ = 9;
					Upgrade();
				};
	
	// --- Auto Build ------------------------------------------------------
	if (Data->you.fabrics == 0)
		if (make_ == 0)
			if (Data->you.money > (Data->you.auto_plants * 15000) )
			{
				make_ = 2;
				turn_ = 7;
				ABuild();
			}
				
// -------------------------
	
	Buy(buy_n,raw_price);
	Sell(sell_n,prod_price);
	Prod(prod_n);

		if (make_ > 0)	printf("	~Robot: making %d, elapsed %d turns.\n", make_, turn_);

	Turn();
};


void CRobot :: Turn()
{
	printf("	~Robot: Turn! \n");
	Socket->SendCommand(COMMAND_ROBOT_TURN);
};


void CRobot :: Upgrade()
{
	printf("	~Robot: Upgrade. \n");
	Socket->SendCommand(COMMAND_ROBOT_UPGRADE);
};


void CRobot :: ABuild()
{
	printf("	~Robot: Auto plant build. \n");
	Socket->SendCommand(COMMAND_ROBOT_ABUILD);
};


void CRobot :: Prod(int n)
{
	printf("	~Robot: prod %d.\n", n);
	Socket->SendCommandWithInt(COMMAND_ROBOT_PROD, n);
}


void CRobot :: Sell(int n, int cost)
{
	printf("	~Robot: sell %d by %d$.\n", n, cost);
	Socket->SendCommandWithInt2(COMMAND_ROBOT_SELL, n, cost);
}


void CRobot :: Buy(int n, int cost)
{
	printf("	~Robot: buy %d by %d$.\n", n, cost);
	Socket->SendCommandWithInt2(COMMAND_ROBOT_BUY, n, cost);
}



//--- MACROSES ---//
int CRobot :: IsWin()
{
	if (Data -> win == 1) printf("~Game: %s won! :-) \n", Data->you.gamer_name);
	if (Data -> win == -1) printf("~Game: %s looser! :'-( \n", Data->you.gamer_name);
	if (Data -> win ==  0)  printf("~Game: %s is playing... :-* \n", Data->you.gamer_name);
 return Data -> win;
};


int CRobot :: IsNeedInAutoPlants()
{
	return Data->you.fabrics;
};


int CRobot :: GetAllPlayers_Prod()
{
	int tmp = 0;
	
	for (int i = 0; i<Data->players_count; i++)
		if (IsPlayerPlaying(Data->players[i]))
			tmp += Data->players[i].prod;

	tmp += Data->you.prod;

 return tmp;
};


int CRobot :: GetAllPlayers_Raw()
{
	int tmp = 0;
	
	for (int i = 0; i<Data->players_count; i++)
		if (IsPlayerPlaying(Data->players[i]))	
			tmp += Data->players[i].raw;

	tmp += Data->you.raw;

 return tmp;
};


int CRobot :: GetAllPlayers_Producing()
{
	int tmp = 0;
	
	for (int i = 0; i<Data->players_count; i++)
	  if (IsPlayerPlaying(Data->players[i]))
		if (MaxProducing(Data->players[i]) > Data->players[i].raw)
		 tmp += Data->players[i].raw;
		else 
		 tmp += MaxProducing(Data->players[i]);

	tmp += MaxProducing(Data->you);

 return tmp;
};


int CRobot :: GetPlayerOptimalBuyN(CGamer &player, int to_prod)
{
	int max = MaxProducing(player);
	if (to_prod < max)
			return max;
		else  
			return 2 * max - to_prod;
};


int CRobot :: GetPlayerOptimalProdN(CGamer &player)
{
	int tmp = MaxProducing(player);
	int prod_n = 0;
		
		if (player.raw < tmp) 
			prod_n = player.raw;
				else  
					prod_n = tmp;
	
 return prod_n;
};


int CRobot :: GetClearProfit(CGamer &player, int sell_price)
{
	if  ((sell_price > Data->market.max_prod_price) && (sell_price <= 0)) 
		return 0;

	double profit = 0;
	double prod_leave = Data->market.prod - GetAllPlayers_Prod();

	double prod_succ = 0;	// 100% will be sold
	double prod_notsucc = 0;	// [probab]% will be sold
	double prod_probab = 0;	// calculated with good_probab

	double prod_will_trade = 0;
	double prod_will_keep = 0;

double probab;
static int tmp;
int i;
	int res = 0;

//	// --- CASE : ALL OK
		if (prod_leave >= 0)
			profit = player.prod * sell_price; // All prod will be sold

//	// --- CASE : NO PLACES FOR PRODUCTION ON THE MARKET
		if (prod_leave < 0) 
		{
			//---------------------------------------------------//			
			int n = 10;
			spoint *good_probab = new spoint [n];

				good_probab[0].x = 0;
				good_probab[0].p = 1;

				good_probab[1].x = Data->market.min_raw_price;
				good_probab[1].p = 0.900;

				good_probab[2].x = 0.3 * Data->market.max_prod_price;
				good_probab[2].p = 0.700;
				
				good_probab[3].x = 0.4 * Data->market.max_prod_price;
				good_probab[3].p = 0.480;

				good_probab[4].x = 0.5 * Data->market.max_prod_price;
				good_probab[4].p = 0.200;

				good_probab[5].x = 0.55 * Data->market.max_prod_price;
				good_probab[5].p = 0.150;

				good_probab[6].x = 0.6 * Data->market.max_prod_price;
				good_probab[6].p = 0.060;

				good_probab[7].x = 0.7 * Data->market.max_prod_price;
				good_probab[7].p = 0.009;

				good_probab[8].x = 0.8 * Data->market.max_prod_price;
				good_probab[8].p = -0.05;

				good_probab[9].x = Data->market.max_prod_price;
				good_probab[9].p = -0.1;

				

			//===================================================//

				
				for (i = 0; i < n-1; i++)
					if  ((good_probab[i].x < sell_price) && (good_probab[i+1].x >= sell_price))
						break;

				double percent = (double) (sell_price - good_probab[i].x) / (double) (good_probab[i+1].x - good_probab[i].x);
				 /*!!!*/ probab = good_probab[i].p + (good_probab[i+1].p - good_probab[i].p) * percent;

				
				
					prod_succ = NotLess0( prod_leave + player.prod ); 
					prod_notsucc = player.prod - prod_succ;
				
				prod_probab = (int) (probab * (double) prod_notsucc);
				
				prod_will_trade = prod_succ + prod_probab;
				prod_will_keep = player.prod - prod_will_trade;

				profit = prod_will_trade * sell_price;

			delete [] good_probab;
		}		

//	//--- RESULT
	//	By conditions: prod (raw)
	int loss = (int) prod_will_keep * PRICE_KEEPING_PROD;
		//(int) NotLess0(player.raw - MaxProducing(player)) * PRICE_KEEPING_RAW +	// min
		
		//player.fabrics*PRICE_KEEPING_PLANT + player.auto_plants*PRICE_KEEPING_AUTO		

		
	res = player.money + (int) profit - loss;
	//res = loss;
	
	return res;
};



int CRobot :: GetPlayingGamers()
{ 
	int tmp = 0;
	for(int i = 0; i < Data->players_count; i++)
		tmp += IsPlayerPlaying(Data->players[i]);
	
 return tmp+1;
}
int CRobot :: MaxProducing(CGamer &player)
{
	return player.fabrics + 2*player.auto_plants;
}
//--- HUMOR ---//
void CRobot :: DeadPlayers()
{

	for (int i = 0; i<Data->players_count; i++)
	{
//		if (Data->players[i].fa

	}

};









//--- helpers ---//
	double NotLess0(double a)
{
	if (a < 0) return 0; 
	else return a;
};


	int IsPlayerPlaying(CGamer &p)
	{
		if (p.money != -1) return 1;
		else return 0;
	}

	
	void N_F(double sigma, double a, spoint *g, int n, int inverse)
	{
		double first = (1 / (PI2 * sigma));
		double sigma2 = (2 * sigma);
		double I = 0;

			for (int i = 0; i<n; i++)
			{
				g[i].p = I + first * exp( -pow(g[i].x - a, 2) / sigma2 );
				I += g[i].p;
			}

	
			if (inverse) 
				for (int i = 0; i<n; i++)
					g[i].p = 1.0 - g[i].p;
	}