#define RANDOM_FUNC_1(min, max, nb)				((min) + (((max)-(min))/100.0)*(pow((float)(nb)-50.0, 3.0)/2500.0 + 50.0))
#define RANDOM_FUNC_2(min, max, nb)				((min) + (((max)-(min))/100.0)*(nb))

#define CROSS_NOW_NO		0
#define CROSS_NOW_AVERAGE   1
#define CROSS_NOW_GENE		2

class Gene {
public:
	float probability;
	bool change;
	Gene() {
		probability = 0.0;
		change = false;
	}
};

void Personality::ModifyFile(char *input_name, char *cross_name, char *output_name) {

	const int rank_size = 4096;
	FILE *input_file, *output_file, *cross_file;		
	char *rank = (char*) malloc(rank_size * sizeof(char));
	char *str = (char*) malloc(rank_size * sizeof(char));
		
	char symb;
	char mut_nb[64];
	float tmp, interval[] = {0.0, 0.0}; 
	int gi = 0, i, k, rnd, max_group = 0;	// gi - gene index
	bool start = true, comment = false, number = false;
	int global_rnd = rand() % 100;
	int global_rnd_2 = rand() % 100;
	origin = '?';

	Gene *gene = (Gene*) malloc(max_groups * sizeof(Gene));

	input_file = fopen(input_name, "r");
	if (!input_file) {
		printf("[ModifyFile] Cant open %s . Aborted...\n", input_name);	
		return;
	}	
	fseek(input_file, 0, SEEK_SET);
	output_file = fopen(output_name,"w+");

	// crossing	
	int cross_index = 0;	
	const int max_param = 4096;
	double *c_prm = (double*) malloc((max_param) * sizeof(double));
	char *c_result = (char*) malloc(128 * max_param * sizeof(char));
	cross_file = fopen(cross_name, "r");
	if (!cross_file) {
		printf("[ModifyFile] Cant open Cross %s . Aborted...\n", cross_name);	
		return;
	}
	c_result[0] = '\0';
	fseek(cross_file, 0, SEEK_SET);
	while(fgets(rank, rank_size, cross_file)) {
		strcat(c_result, rank);
	}
	ParseParams(c_result, c_prm, false);

	while(fgets(rank, rank_size, input_file)) {			
		if(start) {			
			if(rank[0] == 'G') { 	
				sscanf(rank, "G%d", &gi);
				sscanf(rank, "G%d %f", &gi, &gene[gi].probability);
				gene[gi].change = false;
				max_group = MAX(max_group, gi);
			}
			if(rank[0] == 'E' && rank[1] == 'N' && rank[2] == 'D') {
				start = false;
				int g;
				float summ = 0.0;
				for(g = 0; g <= max_group; g++) {
					cross_table[g] = -1;
				}
				for(g = 0; g <= 1; g++) {
					while(m_ind[g]-- > 0) {						
						if(cross_table[ m_hist[g][m_ind[g]] ] == -1) {
							cross_table[ m_hist[g][m_ind[g]] ] = g;
						}
					}
				}
				for(g = 0; g <= max_group; g++) {
					summ += gene[g].probability;
					if(cross_now == CROSS_NOW_GENE) {
						if(cross_table[g] == -1)
							cross_table[g] = rand() % 2;						
						printf("%d", cross_table[g]);
					}
				}
				mutated_gene = -1;
				for(g = 0; g <= max_group; g++) {
					if(((gene[g].probability / summ) * 1000.0) > (rand() % 1000)) {
						gene[g].change = true;
						mutated_gene = g;
						if(cross_now == CROSS_NOW_NO)		{	printf("G%d", g)			;}
						if(cross_now == CROSS_NOW_AVERAGE)  {	printf("(%.3f)", crossing)	;}
						break;
					} else	summ -= gene[g].probability;
				}
				ASSERT(gene[g].change == true);
			}
			strcpy(str, rank);
		} else {
			for(i = 0, k = 0; i < strlen(rank); i++) {
				symb = rank[i];
				str[k] = '\0';
				if(comment)	{	
					if((str[k++] = symb) == '>' || symb == ']')	comment = false;
				} else {
					if(symb == '<')	{comment = true; number = false; str[k++] = symb;
					} else if(symb == '[') {
						comment = true; number = false; str[k++] = symb; 
						sscanf(rank+i, "[%f %f]", &interval[0], &interval[1]);						
					} else if(symb == '#') {
						number = false;
						sscanf(rank+i, "#%d", &gi);
						sprintf(mut_nb, "#%d", gi);
						strcat(str, mut_nb);
						k += strlen(mut_nb);
						i += strlen(mut_nb)-1;
					} else if((isdigit(symb) || symb == '-' || symb == '.')) {
						if(number)	continue;
						number = true;
						tmp = atof(rank + i);
						rnd = rand() % 100;
						
						if(cross_now == CROSS_NOW_AVERAGE) {
							tmp = (tmp + c_prm[cross_index++]) / 2.0;
							origin = 'A';
						} else if(cross_now == CROSS_NOW_GENE) {								
							if(cross_table[gi] == 1)
								tmp = c_prm[cross_index];
							cross_index++;
							origin = 'G';
						} else if(gene[gi].change) {
							if((global_rnd_2 % 100) < rand_prob) {
								origin = 'r';
								tmp = RANDOM_FUNC_1(interval[0], interval[1], rnd);
							} else {
								if((global_rnd % 100) < one_sign_prob) {	
									tmp += (interval[0]-interval[1]) * sign[global_rnd % 2] * RANDOM_FUNC_2(0, interval_step, global_rnd);
									origin = 's';
								} else {
									tmp += (interval[0]-interval[1]) * sign[rnd%2] * RANDOM_FUNC_1(0, interval_step, rnd);
									origin = 'm';
								}
							}
						}
						sprintf(mut_nb, "%.3f", tmp);						
						strcat(str, mut_nb);
						k += strlen(mut_nb);						
					} else {
						number = false;
						str[k++] = symb;
					}
				}				
			}			
			str[k] = '\0';
		}
		fputs(str, output_file);
	}	
	
	free(c_result); 
	free(c_prm);
	free(rank);
	free(str);
	free(gene);
	fclose(output_file);
	fclose(input_file);
	fclose(cross_file);
}

class Auto {
public:
	static const int max_players = 128, stsc = 10, bsc = 5;
	int players, newborns, cycles, depth;
	char file_name[max_players][128];	
	float score[max_players];
	float stand_score[stsc];
	int history[max_players];
	char origin[max_players];
	char last_result[128];
	int sort[max_players];
	float fast_win_bonus;
	float safety_ratio;
	int standart;
	int tourn_nb;
	FILE *log;	
	FILE *openings;
	FILE *file[max_players];
	float max_history_inc;
	int max_history_age;
	int model_advantage;
	static const int mh_max = 5;
	uint8 mh_index[max_players];
	sint16 mut_hist[max_players][mh_max];
	double av_file_diff;
	int file_diff_nb;
	float (*best_sc)[bsc];

	Personality ap[1];

	void MultiplyFile(char *input_name);
	void Tournament(Searcher *s, Board *b);
	void Game(Searcher *s, Board *b, char *fen, int white,
		int black, float *w_res, float *b_res);	
	void ParseOpenings(char *fen, int rnd_nb);	
	void Calculate(Searcher *s, Board *b);
	void TournResult();
	void ReadConfig();
	void WriteConfig();
	void SetModelAdvantage(int elo);
	double CompareFiles(Personality *p, char *file_name_1, char *file_name_2);
	void MathModel(Searcher *s, Board *b, FILE *input, char *zero_file, char *stand_file,
					 int pl, int nb, int cy, int mha, float mhi, int ms_time);
	void FileToArray(Searcher *s);
	double Round(double d);
	
	Auto() {
		int i, k;
		char name[128];
				
		players = 40;
		newborns = 20;
		cycles = 1;
		depth = 5;
		standart = 0; //-1;

		best_sc = new float[max_players][bsc];
		model_advantage = 520; // 14 Elo
		max_history_inc = 5.0;
		max_history_age = 10;

		for(i = 0; i < max_players; i++) {
			sprintf(file_name[i], "player %d.txt", i);			
			history[i] = 0;
			score[i] = 0.0;
			mh_index[i] = 0;
			origin[i] = ' ';
			for(k = 0; k < mh_max; k++)
				mut_hist[i][k] = 0;
			for(k = 0; k < bsc; k++)
				best_sc[i][k] = 0.0;
		}
		for(i = 0; i < stsc; i++)
			stand_score[i] = 0.0;

		tourn_nb = 0;
		safety_ratio = 0.0;
		fast_win_bonus = 1.0;
		log = fopen("LOG.txt", "w+");
		openings = fopen("OPENINGS.txt", "r");	
		strcpy(last_result, "no result ");
		av_file_diff = 0.0;
		file_diff_nb = 0;		
	}
};

void Auto::MultiplyFile(char *input_name) {

	int i, rank_size = 4096;
	char *str = (char*) malloc(rank_size * sizeof(char));
	FILE *input_file = fopen(input_name, "r");
	if (!input_file) {
		printf("[MultiplyFile] Cant open . Aborted...\n");	
		return;
	}	
	for(i = 0; i < players; i++) {	
		fseek(input_file, 0, SEEK_SET);
		file[i] = fopen(file_name[i], "w+");
		while(fgets(str, rank_size, input_file)) {
			fputs(str, file[i]);
		}
		fclose(file[i]);
	}
	printf("multiplied\n");
}

char STANDART[] = "STANDART.txt";

void Auto::Tournament(Searcher *s, Board *b) {	
		
	int i, k, cyc, nb = 0, white, black, rnd_op, time;
	char fen[256];	
	s->view = false;	
	rnd_op = rand() & 0xFFFFF;
	time = GetTickCount();

	printf("Tournament %d\n", ++tourn_nb);
	if(GEN_USE_LOG)	fprintf(log, "Tournament %d\n", tourn_nb);

	for(i = 0; i < players; i++) {
		s->person[i]->ParseFile(file_name[i]);
		pawn_info[i].InitStorm(s->person[i]);
		pawn_info[i].InitShelter(s->person[i]);
	} 
	for(cyc = 0; cyc < cycles; cyc++) {		
		for(i = players-1; i >= 0; i--) {			
			for(k = i-1; k >= 0; k--, nb++) {				
				ParseOpenings(fen, rnd_op + (i-k-1) + cyc*(players-1));
				//ParseOpenings(fen, rnd_op + cyc);
				white = (nb%2 == 0) ? i : k;
				black = (nb%2 == 1) ? i : k;								
				Game(s, b, fen, white, black, &(score[white]), &(score[black]));
				printf("\r\r%2d vs %2d (%3d of %3d) %s", white, black, nb+1, cycles*(players-1)*players/2, last_result);
			}
		}
	}		
	TournResult();	

	time = (GetTickCount() - time) / 1000; // sec
	printf("Time %2d min %2d sec\n", time / 60, time % 60);
}

void Auto::Game(Searcher *s, Board *b, char *fen, int white, int black, float *w_res, float *b_res) {
#ifdef MODEL
	if((rand() % 100) < 20) {
		*w_res += 0.5;
		*b_res += 0.5;	
		strcpy(last_result, "1/2 ");
		return;
	}	
	int winner = BLACK;
	double d1, d2;
	if((d1=CompareFiles(s->person[0], file_name[white], STANDART)) < (d2=CompareFiles(s->person[0], file_name[black], STANDART)))	winner = WHITE;
	
	if((rand() % 1000) >= model_advantage)	{
		winner ^= 1; // average advantage = 14 Elo points		
	}
	if(winner == WHITE) {
		*w_res += 1.0;
		*b_res += 0.0;	
		strcpy(last_result, "1-0 ");
	} else {
		*w_res += 0.0;
		*b_res += 1.0;	
		strcpy(last_result, "0-1 ");
	}
#else	
	int hply = 0, draw = 0;
	enum {UNKNOW_RES, WHITE_WIN, BLACK_WIN, DRAW_RES};
	int result = UNKNOW_RES;

	MoveList sm[1];
	undo_t undo[1];
	float fwb = 1.0;	
	if(GEN_USE_LOG) {
		fprintf(log, "[%2d vs %2d]\n", white, black);
		fprintf(log, "%s", fen);		
	}

	// init
	b->FromFEN(fen);
	s->trans->NewGame();
	int time[] = {60000, 60000};
	int depth_limit, node_limit, dec[] = {0,0};

	//node_limit = 7000 + (rand() % 2000);
	//node_limit = 8000;

	for(EVER) {
		s->active_person = (b->stm == WHITE) ? white : black;
		s->trans->auto_side = b->stm;
		s->ActivePerson()->InitPST();
		b->ResetPST();
		sm->Clear();		
		
		node_limit = 0;
		depth_limit = depth;		
		//ASSERT(node_limit >= 4000);
		//ASSERT(node_limit <= 12000);

		s->RootSearch(b, 0, 0, 0, 0, depth_limit, node_limit, 0, 0, 0, 0, 0, sm);
		//time[b->stm] -= s->timer->SearchTime();

		dec[WHITE] = dec[BLACK] = 0;
				
		if(s->data->last_scores[1] == 0)			draw++;  
		else										draw = 0;

		if(hply++ >= (MAX_KEYS-24))					result = DRAW_RES;
		else if(draw >= 6)							result = DRAW_RES;
		else if(sm->Size() == 0 && !b->InCheck())	result = DRAW_RES;
		else if(sm->Size() == 0 && b->InCheck())	result = WHITE_WIN + (b->stm^1);
		else if(time[b->stm] <= 0)					result = WHITE_WIN + (b->stm^1);		
		else if(s->data->last_scores[1] < -900)		result = WHITE_WIN + (b->stm^1);

		if(result != UNKNOW_RES) {
			switch(result) {
				case DRAW_RES:	
					*w_res += 0.5;
					*b_res += 0.5;
					if(GEN_USE_LOG)	fprintf(log, "\n1/2-1/2\n\n");
					strcpy(last_result, "1/2 ");			
					break;
				case WHITE_WIN:	
					*w_res += 1.0;
					*b_res += 0.0;
					if(GEN_USE_LOG)	fprintf(log, "\n1-0\n\n");
					strcpy(last_result, "1-0 ");			
					break;
				case BLACK_WIN:	
					*w_res += 0.0;
					*b_res += 1.0;
					if(GEN_USE_LOG)	fprintf(log, "\n0-1\n\n");
					strcpy(last_result, "0-1 ");			
					break;
				default: ASSERT(false);
			}
			return;
		}
		if(false) {
			printf("\r\r\r[%2d:%2d] wtime %6d btime %6d hply %3d score %6d", 
				white, black, time[WHITE], time[BLACK], hply, s->data->last_scores[1] * sign[b->stm]);
		}		
		if(GEN_USE_LOG)	{
			s->RootBestMove().Print(log);
			fprintf(log, "(%d) ", s->data->last_scores[1] * sign[b->stm]);
		}

		b->MakeMove(&s->RootBestMove(), undo);
		hply++;
	}
#endif
}

void Auto::TournResult() {
	int i, m, k, s, d;
	float max_score; 
	double file_diff;
	float max_out_score = -1.0;
	printf("\r\r#\t#\t#\t#\t#\n");	

	for(i = 0; i < players; i++) {
		max_score = -1.0; 

		// new block
		for(k = 0; k < players; k++) {			
			for(m = 0; m < i; m++) {
				if(k == sort[m]) goto br; 
			}
			float score_k = 0.0; 
			int f, zero = 0;
			for(f = 0; f < bsc; f++) {
				if(best_sc[k][f] == 0.0)	zero++;
				score_k += best_sc[k][f];
			}			
			if(i <= 3) zero = MIN(bsc-1, zero);
			score_k = (score[k] + score_k) / (1+bsc-zero);
			if(score_k > max_score) {
				max_score = score_k;
				sort[i] = k;
			}
			br:	;
		}
		// end

		printf("%2d | %3.1f | player %d\t", i, score[sort[i]], sort[i]);
		best_sc[sort[i]][tourn_nb % bsc] = score[sort[i]];

		if(i >= players - newborns) {
			if(sort[i] != standart) {

				if(standart == sort[0])		 {	s = 1; d = 2;}
				else if(standart == sort[1]) {	s = 0; d = 2;}
				else						 {	s = 0; d = 1;}
				for(k = 0; k < mh_max; k++) {
					ap->m_hist[0][k] = mut_hist[sort[s]][k];		ap->m_ind[0] = mh_index[sort[s]];
					ap->m_hist[1][k] = mut_hist[sort[d]][k];		ap->m_ind[1] = mh_index[sort[d]];
				}

				file_diff = CompareFiles(ap, file_name[sort[s]], file_name[sort[d]]);
				av_file_diff = (av_file_diff*file_diff_nb + file_diff) / (file_diff_nb+1);
				file_diff_nb++;

				if((ap->crossing * ap->averaging_prob * 10.0) > (rand() % 1000)) {
					if((1000.0 * MATH_SQUARE(file_diff)) / MATH_SQUARE(av_file_diff) > (rand() % 2000)) {
						ap->cross_now = CROSS_NOW_GENE;					
						printf("crossing: GE [%.1f > %.1f] ", file_diff, av_file_diff);
					} else {
						ap->cross_now = CROSS_NOW_AVERAGE;					
						printf("crossing: AV [%.1f > %.1f] ", file_diff, av_file_diff);
					}				
				} else {
					ap->cross_now = CROSS_NOW_NO;					
					printf("crossing: no ");
				}

				ap->ModifyFile(file_name[sort[s]], file_name[sort[d]], file_name[sort[i]]);
				history[sort[i]] = tourn_nb;
				origin[sort[i]] = ap->origin;

				ASSERT(ap->mh_size >= mh_max);
				if(ap->cross_now != CROSS_NOW_NO) {
					mh_index[sort[i]] = 0;
				} else {
					for(k = 0; k < mh_index[sort[s]]; k++) 
						mut_hist[sort[i]][k] = mut_hist[sort[s]][k];
					mut_hist[sort[i]][k] = ap->mutated_gene;
					mh_index[sort[i]] = k + 1;
					if(mh_index[sort[i]] >= mh_max)	{
						mh_index[sort[i]] = 1;
						mut_hist[sort[i]][0] = ap->mutated_gene;
					}
				}
				// best_sc
				for(k = 0; k < bsc; k++) 
					best_sc[sort[i]][k] = 0.0;
				
				max_out_score = MAX(max_out_score, score[sort[i]]);
			} else printf("standart");
		}
		printf(" <%d> %c\n", history[sort[i]], origin[sort[i]]);
	}	
	if(standart != -1) {
		float tmp = 0.0;
		stand_score[tourn_nb % stsc] = score[standart];
		for(i = 0; i < stsc; i++) tmp += stand_score[i];
		printf("Standart score %.3f\n", tmp / stsc);
	}
	for(i = 0; i < players; i++) {
		score[sort[i]] *= safety_ratio;
		score[sort[i]] = MAX(score[sort[i]], max_out_score * safety_ratio);
		score[sort[i]] += max_history_inc * MIN(tourn_nb - history[sort[i]], max_history_age) / MAX(max_history_age, 1);		
	}
	// best_sc
	int best_nb = -1;
	float max_best = 0.0, ftmp;
	for(i = 0; i < players; i++) {
		ftmp = 0.0;
		for(k = 0; k < bsc; k++) {
			ftmp += best_sc[i][k];
		}
		if(ftmp > max_best) {
			max_best = ftmp;
			best_nb = i;
		}
	}
	printf("Best version %d   Score %.2f\n", best_nb, max_best / bsc);
	
	WriteConfig();
#ifdef MODEL
	if(standart == sort[0])		printf("RESULT %.3f\n", CompareFiles(ap, file_name[sort[1]], STANDART));
	else						printf("RESULT %.3f\n", CompareFiles(ap, file_name[sort[0]], STANDART));
#endif	
}

void Auto::ParseOpenings(char *fen, int rnd_nb) {

	const int rank_size = 512;
	int max_openings = 0, i = 0, k;
	char *rank = (char*) malloc(rank_size * sizeof(char));

	fseek(openings, 0, SEEK_SET);
	while(fgets(rank, rank_size, openings)) {
		max_openings++;
	}	
	k = rnd_nb % max_openings;
	fseek(openings, 0, SEEK_SET);
	while(i++ <= k) {
		fgets(rank, rank_size, openings);
	}
	strcpy(fen, rank);
	free(rank);
}

void Auto::Calculate(Searcher *s, Board *b) {
	
	int i, rank_size = 4096;
	char *str = (char*) malloc(rank_size * sizeof(char));
	FILE *output_file, *f;
	char input_name[256];
	WIN32_FIND_DATA ffd;

	ReadConfig();
	s->locked_view = true;
	srand((int)GetTickCount());
	//srand(1);
	ASSERT(players <= MAX_PERSONS);
	
	for(EVER) {
		Tournament(s, b);
		i = 0;
		do { sprintf(input_name, "WINNER %d.txt", i++);
		} while(FindFirstFile(input_name, &ffd) != INVALID_HANDLE_VALUE);
	
		if(sort[0] == standart)		output_file = fopen(file_name[sort[1]], "r");
		else						output_file = fopen(file_name[sort[0]], "r");
		f = fopen(input_name, "w+");
		if(!output_file) {
			printf("[Calculate] Cant open . Aborted...\n");	
			return;
		}			
		fseek(output_file, 0, SEEK_SET);		
		while(fgets(str, rank_size, output_file)) {
			fputs(str, f);
		}
		fclose(output_file);
		fclose(f);		
		printf("\n");
	}
}

double Auto::CompareFiles(Personality *p, char *file_name_1, char *file_name_2) {
	// assume file_name_2 = STANDART

	const int max_param = 4096, rank_size = 4096, total = 120;
	char *rank = (char*) malloc(rank_size * sizeof(char));
	double *prm_1 = (double*) malloc((max_param) * sizeof(double));
	double *prm_2 = (double*) malloc((max_param) * sizeof(double));
	char *c_result = (char*) malloc(128 * max_param * sizeof(char));
	FILE *file_1 = fopen(file_name_1, "r");
	FILE *file_2 = fopen(file_name_2, "r");
	if ((!file_1) || (!file_2)) {
		printf("[CompareFiles] Cant open . Aborted...\n");	
		return 0.0;
	}
	
	fseek(file_1, 0, SEEK_SET);
	fseek(file_2, 0, SEEK_SET);

	c_result[0] = '\0';
	while(fgets(rank, rank_size, file_1)) {
		strcat(c_result, rank);
	}
	p->ParseParams(c_result, prm_1, false);
	c_result[0] = '\0';
	while(fgets(rank, rank_size, file_2)) {
		strcat(c_result, rank);
	}
	p->ParseParams(c_result, prm_2, false);
	delete c_result;

	double res = 1.0, tmp, ab, rat;
	for(int i = 0; i < total; i++) {
		tmp = prm_1[i] - prm_2[i];

		ab = ABS(prm_2[i]);
		if(ab == 0.0)	ab = 1.0;
		rat = 10.0 * pow(10, (-2.0)*log10(ab));
		ASSERT(rat > 0.0);

		res += tmp*tmp * rat;
	}

	delete prm_1;
	delete prm_2;
	delete rank;
	fclose(file_1);
	fclose(file_2);
	return pow(res, 0.5);
}

void Auto::MathModel(Searcher *s, Board *b, FILE *input, char *zero_file, char *stand_file,
					 int pl, int nb, int cy, int mha, float mhi, int ms_time) {	
	int i, k;
	cycles = cy;
	players = pl;
	newborns = nb;
	max_history_inc = mhi;
	max_history_age = mha;
	tourn_nb = 0;
	
	fprintf(input, " players %d\n newborns %d\n cycles %d\n mhi %.2f\n mha %d\n time %d sec\n Elo diff %d\n",
		pl, nb, cy, mhi, mha, ms_time/1000, model_advantage);
	fprintf(input, " rand_prob %d\t crossing %.2f\t one_sign_prob %d\t averaging_prob %d\t interval_step %.2f\n", 
		ap->rand_prob, ap->crossing, ap->one_sign_prob, ap->averaging_prob, ap->interval_step);

	MultiplyFile(zero_file);
	players = 1;
	MultiplyFile(stand_file);
	players = pl;
	
	const int bnb = MIN(5, players-1);
	double start = 0.0, finish = 0.0;
	double best[max_players], tmp, top = 0.0;	

	for(i = 1; i < players; i++) {
		start += CompareFiles(s->person[0], file_name[i], file_name[0]);		
		sprintf(file_name[i], "player %d.txt", i);			
		history[i] = 0;
		score[i] = 0.0;
		best[i-1] = 10000.0;
	}
	
	int time = (int)GetTickCount();
	srand(time);
	while(time + ms_time > (int)GetTickCount()) {
		Tournament(s, b);
	}

	for(i = 1; i < players; i++) {
		finish += (best[i-1] = CompareFiles(s->person[0], file_name[i], file_name[0]));		
	}

	fprintf(input, "Best versions:\n");
	for(i = 0; i < players-1; i++) {
		for(k = i; k < players-1; k++) {
			if(best[k] < best[i]) {
				tmp = best[i];
				best[i] = best[k];
				best[k] = tmp;
			}
		}
		if(i < bnb) {	
			fprintf(input, "%3d) %.3f\n", i+1,  best[i]);
			top += best[i];
		}
	}

	fprintf(input, "Best %d players average score %.3f\n", bnb, top /= (double)bnb);
	fprintf(input, "Average start difference %.3f\n", start /= (players-1));
	fprintf(input, "Average finish difference %.3f\n", finish /= (players-1));
	fprintf(input, "Final methods difference %.3f\n", start - finish);
	fprintf(input, "Final methods best %d players diff %.3f\n", bnb, start - top);
	fprintf(input, "Tournaments %d\n", tourn_nb);
	fprintf(input, "------------------//------------------//------------------\n");
	
	Auto();
	ap->Reset();
}


void Auto::ReadConfig() {

	char *string = (char*) malloc(4096 * sizeof(char));
	FILE *cfg = fopen("Config.txt", "r");
	int dtmp, htmp;
	float ftmp;		
	
	if(!cfg) 	printf("Can`t find Config.txt. Aborted\n");

	while(fgets(string, 4096, cfg)) {
		if(STRING_START_WITH("pl(")) {
			sscanf(string, "pl(%d) nb(%d) cy(%d) depth(%d) stand(%d) mhi(%f) mha(%d)",
				   &players, &newborns, &cycles, &depth, &standart, &max_history_inc, &max_history_age);
			players = MIN(players, max_players);
			newborns = MIN(newborns, players-3);
			cycles = MAX(1, cycles);
			depth = MAX(1, depth);
		} else if(STRING_START_WITH("rand_prob (")) {
			sscanf(string, "rand_prob (%d) crossing (%f) one_sign_prob (%d) averaging_prob (%d) interval_step (%f) SR (%f) FWB (%f)",
					&ap->rand_prob, &ap->crossing, &ap->one_sign_prob, &ap->averaging_prob, &ap->interval_step, &safety_ratio, &fast_win_bonus);
		} else if(STRING_START_WITH("tournament (")) {
			sscanf(string, "tournament (%d)", &tourn_nb);
		} else if(STRING_START_WITH("f[")) {
			sscanf(string, "f[%d] %f %d", &dtmp, &ftmp, &htmp);
			dtmp = dtmp % max_players;			
			history[dtmp] = MAX(htmp, 0);
			score[dtmp] = MAX(ftmp, max_history_inc * MIN(tourn_nb - history[dtmp], max_history_age) / MAX(max_history_age, 1));
		}
	}
	fclose(cfg);
	free(string);
	printf("pl(%d) nb(%d) cy(%d) depth(%d) stand(%d) mhi(%.2f) mha(%d)\n", 
			players, newborns, cycles, depth, standart, max_history_inc, max_history_age);
	printf("rand_prob (%d) crossing (%.2f) one_sign_prob (%d) averaging_prob (%d) interval_step (%.2f) SR (%.2f) FWB (%.2f)\n",
			ap->rand_prob, ap->crossing, ap->one_sign_prob, ap->averaging_prob, ap->interval_step, safety_ratio, fast_win_bonus);
}

void Auto::WriteConfig() {
	char *string = (char*) malloc(4096 * sizeof(char));
	char *str_1 = (char*) malloc(4096 * sizeof(char));
	char *str_2 = (char*) malloc(4096 * sizeof(char));
	FILE *cfg = fopen("Config.txt", "r");
	if(!cfg) 	printf("\n\nCan`t open Config.txt. Aborted\n");

	while(fgets(string, 4096, cfg)) {
		if(STRING_START_WITH("pl(")) {
			strcpy(str_1, string);
		} else if(STRING_START_WITH("rand_prob (")) {
			strcpy(str_2, string);
		}
	}
	fclose(cfg);

	cfg = fopen("Config.txt", "w+");
	if(!cfg) 	printf("\n\nCan`t re-write Config.txt. Aborted\n");

	fprintf(cfg, "tournament (%d)\n", tourn_nb);
	fputs(str_1, cfg);
	fputs(str_2, cfg);

	for(int i = 0; i < players; i++) {
		fprintf(cfg, "f[%d] %.3f %d\n", i, score[i], history[i]);
	}

	fclose(cfg);
	free(string);
	free(str_1);
	free(str_2);
}

void Auto::SetModelAdvantage(int elo) {	
	model_advantage = int(1000.0 / (1.0 + pow(10.0, (float)elo / 400.0)));
	model_advantage = MAX(model_advantage, 1000 - model_advantage);
	printf("model adv sets to %d (%d Elo)\n", model_advantage, elo);
}

void Auto::FileToArray(Searcher *s) {

	int i;
	FILE *output;
	FILE *input = fopen("ARRAY.txt","w+");
	const int max_param = 4096, max_char = 16384;
	double *result = (double*) malloc((max_param) * sizeof(double));

	// file -> char
	char file_name[512], tmp[512];
	int rank_size = max_char / 8;
	// Char ARRay
	char *carr = (char*) malloc(max_char * sizeof(char));
	char *rank = (char*) malloc(rank_size * sizeof(char));
	memset(carr, 0, sizeof(carr));
	
	printf("Input file name\n");
	fgets(tmp, 512, stdin);
	sscanf(tmp, "%s", file_name);
	printf("%s\n\n", file_name);
	output = fopen(file_name, "r");	
	
	fseek(output, 0, SEEK_SET);
	while(fgets(rank, rank_size, output)) {
		strcat(carr, rank);
	}
	// char -> double
	for(i = 0; i < max_param; i++)		result[i] = 0.0;	
	s->person[s->active_person]->ParseParams(carr, result, false);

	// print
	fprintf(input, "\tdouble EvParameter[] = {\n\t\t");
	char *format[2] = {" ", "\n\t\t"}; 

	for(i = 0; i < max_param; i++) {
		if(result[i] == 0.0)	break;
		printf("%8.3f     %.3f\n", result[i], Round(result[i]));
		if(result[i+1] == 0.0)			fprintf(input, "%8.3f\n", Round(result[i]));
		else		fprintf(input, "%8.3f,%s", Round(result[i]), format[i%8 == 7]);
	}
	fprintf(input, "\t};");
	printf("pointer = %d\n", i);
}

double Auto::Round(double d) {

	int i;
	double res;
	int rat = 1.0; 
	
	res = ABS(d);
	if(res > 10.0)			rat = 10000;
	else if(res > 1.0)		rat = 1000;
	else if(res > 0.1)		rat = 100;
	else if(res > 0.01)		rat = 10;

	i = d * 10000.0;
	i /= rat;
	i *= rat;
	res = i / 10000.0;

	return res;
}