// Berkeley Open Infrastructure for Network Computing
// http://boinc.berkeley.edu
// Copyright (C) 2007 University of California
//
// This is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation;
// either version 2.1 of the License, or (at your option) any later version.
//
// This software is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Lesser General Public License for more details.
//
// To view the GNU Lesser General Public License visit
// http://www.gnu.org/copyleft/lesser.html
// or write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


//RamseyApp.C - 1.16
//Nick Peterson

#ifdef _WIN32
#include "boinc_win.h"
#else
#include "config.h"
#include <cstdio>
#include <cctype>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <csignal>
#include <unistd.h>
#endif

#include <fstream>
#include <cstring>
#include <iostream>
#include <sstream>
#include "str_util.h"
#include "util.h"
#include "filesys.h"
#include "boinc_api.h"
#include "mfile.h"
#include "graphics2.h"

#ifdef APP_GRAPHICS
#include "uc2.h"
UC_SHMEM* shmem;
#endif

using namespace std;

#define RAND_MASK       0x000003FF
#define CHECKPOINT_FILE "ramsey_state"
#define INPUT_FILENAME "in"
#define OUTPUT_FILENAME "out"

int do_checkpoint(int chromo[][168], int bestStopped, double bestEval, int ITERATIONS, int PARTITIONS, int POINTS);
void SetRand (int seed);
static int gRandom (void);
int GetRand (void);

int do_checkpoint(int chromo[][168], int bestStopped, double bestEval, int ITERATIONS, int PARTITIONS, int POINTS) {
MFILE chk;
char chkpt_path2[512];
boinc_resolve_filename(CHECKPOINT_FILE, chkpt_path2, sizeof(chkpt_path2));

	chk.open(chkpt_path2, "wb");

	stringstream ss;

	for(int j = 0; j < PARTITIONS; j++)
		{
		for(int k = 0; k < POINTS; k++)
			{
			if(chromo[j][k] == 0)
				break;

			ss << chromo[j][k] << ' ';
			}

		ss << " ; ";
		}

	ss << bestStopped << ' ' << bestEval << ' ' << ITERATIONS << ' ';
	chk.puts(ss.str().c_str());
	chk.close();
return 0;
}

#ifdef APP_GRAPHICS
void update_shmem() {
	if (!shmem) return;

	// Check whether a graphics app is running,
	// and don't bother updating shmem if so.
	// This doesn't matter here,
	// but may be worth doing if updating shmem is expensive.
	//
	if (shmem->countdown > 0) {
		// the graphics app sets this to 5 every time it renders a frame
		shmem->countdown--;
		} else {
			return;
		}
	shmem->fraction_done = boinc_get_fraction_done();
	shmem->cpu_time = boinc_worker_thread_cpu_time();;
	shmem->update_time = dtime();
	boinc_get_status(&shmem->status);
	}
#endif

//I'm using Mr. Redding's code to generate random numbers in the interest of consistancy across
//platforms. Thanks Mark!
/*
Genetic Life
Copyright (C) 2008 , Mark W J Redding

Genetic Life is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

static int randpos;

static int randlist[] = { 1000,
  83474, 4114, 24570, 99579, 55635, 47085, 70706, 72805, 31202, 54036,
  43071, 50402, 30950, 75654, 74987, 30602, 60074, 39485, 42166, 94780,
  53473, 65256, 48151, 26084, 16787, 52554, 27270, 35951, 85818, 5313,
  59798, 57136, 46827, 74227, 44929, 52077, 32834, 7337, 59422, 2244,
  97315, 68165, 66126, 71566, 58377, 23439, 82024, 15610, 26344, 96727,
  87286, 16017, 90405, 97039, 72043, 22823, 32609, 67768, 16281, 23681,
  588, 22149, 56231, 58905, 72394, 67109, 45893, 19313, 88921, 1280,
  72937, 65203, 88602, 85996, 7554, 37866, 43571, 98004, 12848, 93746,
  35202, 43322, 68324, 8833, 2912, 26588, 43213, 10322, 66188, 87936,
  16377, 48586, 59536, 80486, 73892, 47073, 60892, 35734, 8987, 82773,
  9882, 36593, 98535, 80902, 68052, 79626, 95475, 8114, 22020, 83725,
  45635, 43510, 89632, 75296, 2171, 44004, 85061, 16027, 11395, 59127,
  18486, 337, 10885, 9691, 38679, 71279, 53008, 32290, 88044, 61967,
  40803, 37924, 76948, 692, 5825, 91751, 98095, 98824, 45654, 78118,
  47510, 6520, 55205, 54844, 86460, 3333, 52598, 37975, 3258, 71630,
  36604, 18936, 16750, 92925, 53381, 581, 56974, 60410, 44038, 80896,
  51027, 15711, 32517, 69400, 81881, 64925, 42249, 31107, 40567, 66234,
  56652, 73125, 94238, 20506, 7230, 47048, 26194, 35699, 76351, 69269,
  21417, 81135, 31366, 15583, 54481, 78233, 50848, 9404, 12350, 64023,
  69841, 76971, 74825, 79629, 77418, 12341, 49044, 95376, 45949, 63182,
  96683, 63484, 95466, 11711, 73888, 30733, 9997, 20171, 47984, 27758,
  75626, 66287, 59140, 50467, 65097, 76297, 8214, 71809, 89127, 69578,
  81845, 99415, 28899, 28670, 99137, 5206, 22410, 93928, 22691, 35436,
  2772, 84210, 76862, 34569, 87000, 19623, 65758, 46360, 47172, 32021,
  39287, 55487, 35321, 85608, 61791, 78884, 70405, 57296, 43501, 34834,
  70790, 15164, 74300, 68092, 57262, 80789, 11558, 58609, 59783, 87048,
  87150, 45182, 55386, 93824, 21017, 56727, 57371, 3821, 61358, 88334,
  8653, 46386, 12929, 28739, 54643, 17959, 10413, 87624, 53144, 38645,
  49663, 18484, 97724, 56071, 29017, 17376, 88881, 90694, 94702, 5717,
  40701, 88446, 55275, 80642, 45917, 14720, 15983, 85551, 62651, 60602,
  80496, 47325, 56569, 18530, 65907, 207, 88970, 6793, 72444, 26415,
  85445, 22645, 73009, 80208, 89066, 40786, 58438, 88448, 2186, 56085,
  40807, 3506, 58753, 95155, 7202, 6174, 10210, 66774, 65424, 86154,
  83599, 63095, 85343, 28031, 99849, 80649, 58021, 17562, 56737, 9003,
  23250, 394, 16730, 86017, 4524, 25723, 69218, 8202, 76452, 22890,
  55533, 35267, 59986, 82351, 33565, 11561, 10361, 39157, 18686, 80667,
  64573, 40241, 6277, 89988, 53767, 47945, 96983, 87873, 63767, 86605,
  8403, 92021, 91266, 53796, 46855, 32208, 80484, 52794, 22304, 99203,
  98946, 27032, 44810, 98902, 3307, 35078, 87329, 25248, 9256, 61188,
  62880, 17767, 57978, 11760, 24565, 97228, 1388, 93969, 44826, 1477,
  5545, 30879, 6705, 71578, 46913, 85593, 60370, 80095, 68565, 58989,
  69286, 6657, 94943, 39130, 27165, 3073, 88283, 28440, 40029, 35423,
  3896, 60847, 56195, 87105, 50310, 21445, 1903, 9900, 96027, 26637,
  6516, 60482, 60913, 2566, 37629, 84814, 51863, 26391, 91086, 84723,
  23429, 82295, 23772, 95780, 83089, 55439, 73962, 14839, 48721, 7164,
  90723, 17322, 39851, 16766, 54839, 82343, 7407, 12748, 44534, 35418,
  43195, 70518, 95692, 98901, 19756, 15606, 56615, 79292, 72466, 20371,
  45520, 42167, 67722, 68741, 33977, 22014, 98791, 8951, 51591, 88480,
  74146, 56689, 60132, 51483, 38877, 45315, 66677, 83453, 27854, 36843,
  78181, 19795, 68457, 66479, 59558, 29330, 81695, 86523, 85798, 39389,
  30064, 20837, 33053, 75022, 18098, 93071, 45061, 23027, 34013, 921,
  28889, 6511, 71615, 20395, 91714, 56983, 60213, 84993, 30490, 1268,
  79103, 70112, 98210, 27856, 57013, 20839, 90180, 8388, 82025, 148,
  98989, 84762, 52939, 86468, 15313, 3700, 64055, 62313, 15102, 92729,
  69423, 21571, 9998, 52882, 70526, 51212, 15789, 90987, 35066, 92555,
  53538, 48570, 56078, 90991, 97138, 55297, 9839, 44064, 58319, 89639,
  92098, 38767, 48837, 79778, 60840, 73221, 25564, 22214, 73155, 58829,
  38359, 45126, 31124, 67224, 63548, 28696, 19707, 34689, 57666, 89573,
  88761, 5773, 24977, 86931, 68973, 76280, 21155, 59319, 6543, 96906,
  82795, 71325, 79634, 62827, 80286, 76785, 32977, 70160, 7776, 68028,
  70479, 4370, 68504, 26886, 88675, 97885, 50778, 51910, 54824, 80742,
  50065, 12397, 25678, 12011, 47251, 65032, 88215, 56148, 74705, 43723,
  68855, 2386, 28111, 80136, 82001, 43552, 36079, 39666, 98448, 45627,
  84662, 84128, 87357, 46027, 5499, 38845, 45809, 83050, 49829, 23825,
  69047, 13988, 88898, 81124, 60382, 276, 25359, 77083, 78892, 22884,
  12643, 55483, 89640, 20034, 71948, 21703, 72987, 99518, 24608, 73804,
  26305, 79422, 14103, 30155, 27553, 55557, 42365, 32430, 34917, 56258,
  55107, 77902, 76204, 71525, 65013, 93338, 44139, 48306, 70864, 24366,
  90422, 40582, 17337, 62541, 12650, 11731, 39147, 34393, 47880, 52313,
  22594, 82217, 57238, 55015, 93241, 83417, 72866, 79374, 39387, 32813,
  68331, 44666, 6188, 23303, 52944, 74593, 19508, 61078, 82052, 548,
  72544, 78874, 22444, 15975, 45869, 79370, 39113, 99697, 70573, 72647,
  32030, 88545, 49978, 63701, 99099, 68951, 80425, 73422, 89911, 45562,
  18273, 49935, 11492, 67703, 99895, 22425, 17904, 80118, 79537, 35725,
  68618, 98784, 14055, 1721, 45001, 82819, 85533, 13151, 19343, 21753,
  92795, 5431, 63876, 33323, 25103, 20253, 57178, 30807, 85095, 87931,
  20479, 21541, 22146, 31772, 81638, 7040, 52079, 57637, 15311, 92560,
  58708, 72594, 57102, 7423, 45433, 59340, 77376, 12075, 77153, 17081,
  77204, 3793, 54826, 74741, 99450, 97869, 48411, 24840, 54350, 70619,
  23316, 79511, 95475, 64057, 79775, 1692, 20120, 26897, 77228, 10692,
  8867, 71468, 4498, 58280, 54248, 16152, 9978, 3290, 18964, 25054,
  41208, 53486, 83503, 92865, 15291, 24330, 2759, 20639, 70632, 20663,
  42028, 19279, 37663, 75244, 49863, 19721, 16976, 1234, 74259, 94945,
  62472, 75787, 36651, 83549, 81306, 27520, 63003, 31177, 91481, 75493,
  95013, 62487, 22227, 73871, 54397, 41214, 85904, 92600, 16639, 32026,
  58181, 79189, 25464, 71548, 22768, 99481, 37356, 22486, 50350, 87024,
  39908, 62825, 15610, 16822, 75871, 25471, 6695, 17548, 9371, 95281,
  97166, 31869, 36593, 14260, 74030, 31765, 47638, 96116, 64854, 58506,
  5568, 82920, 74606, 64982, 46534, 4031, 55112, 3570, 36109, 19749,
  9269, 83336, 93637, 57017, 18816, 35632, 24356, 65769, 38843, 64756,
  65779, 36772, 62714, 15561, 98182, 77639, 2106, 33124, 66879, 95183,
  29708, 71324, 12972, 32781, 65136, 57561, 29592, 46137, 44874, 7687,
  22635, 80626, 29386, 68943, 85089, 73708, 75095, 13250, 85134, 98396,
  31857, 23442, 79555, 99246, 97418, 84988, 85320, 46797, 62349, 67037,
  78501, 80756, 88590, 77877, 47130, 60022, 95203, 70414, 28995, 16814,
  66581, 1762, 21403, 65482, 89494, 19749, 65352, 34384, 4851, 52410,
  12952, 72411, 50128, 89256, 22658, 84172, 31470, 99043, 82390, 74594,
  42394, 42894, 5172, 33873, 78377, 74786, 52638, 62004, 38509, 5706,
  18265, 80683, 2631, 36347, 48945, 51924, 89099, 36748, 30869, 33352,
  72397, 81334, 92855, 84145, 51812, 85468, 99973, 44509, 13960, 4563
};


void SetRand (int seed)
{
  randpos = seed;
  return;
}

static int gRandom (void)
{
  if (++randpos > randlist[0])
    randpos = 1;
  return (randlist[randpos]);
}

int GetRand (void)
{
  return ((gRandom () & RAND_MASK));
}


int main(int argc, char **argv) {
	const int CHROMO_PER_POP = 250, PARTITIONS = 5, POINTS = 168, STAGNANT_LEEWAY = 25,
		TIME_TO_CHANGE = 15, DEFAULT_ITERATIONS = 200000;
	int ITERATIONS;
	int population[CHROMO_PER_POP][PARTITIONS][POINTS];
	int bestChromo[PARTITIONS][POINTS];
	double evaluations[CHROMO_PER_POP];
	int stopped[CHROMO_PER_POP];
	int i, iterations = 0;
	int posOfJ[POINTS + 1];
	int offendingNumbers[CHROMO_PER_POP][4];
	int posOfFittest, retval, stagnantIndex = 0, bestStopped = 0;
	double lastFittest = 21.0;
	double bestEval;
	SetRand ( time(NULL) );
	char input_path[512], output_path[512], chkpt_path[512];
	MFILE out;
	FILE* infile;

	retval = boinc_init();
	if (retval) {
		fprintf(stderr, "boinc_init returned %d\n", retval);
		exit(retval);
		}

	// open the input file (resolve logical name first)
	// try to open checkpoint first
	boinc_resolve_filename(CHECKPOINT_FILE, chkpt_path, sizeof(chkpt_path));
	infile = boinc_fopen(chkpt_path, "r");
	if (!infile) {
	boinc_resolve_filename(INPUT_FILENAME, input_path, sizeof(input_path));
	infile = boinc_fopen(input_path, "r");
	if (!infile) {
		fprintf(stderr,
			"Couldn't find input file, resolved name %s.\n", input_path
			);
		exit(-1);
		}
	}

	//Intialize our array from infile
	char partstr [999];
	char * pch;
	int part = 0, index = 0;
	fgets(partstr, 999, infile);

	for(i = 0; i < CHROMO_PER_POP; i++)
		{
		for(int j = 0; j < PARTITIONS; j++)
			{
			for(int k = 0; k < POINTS; k++)
				{
				population[i][j][k] = 0;
				evaluations[i] = 0;
				stopped[i] = 0;
				}
			}
		}
	int counter = 0;
	pch = strtok(partstr, " ");
	while (pch != NULL)
		{
		if(part == 5)
			{
			stopped[0] = atoi(pch);
			pch = strtok (NULL, " ");
			evaluations[0] = atoi(pch);
			pch = strtok (NULL, " ");
			if(pch == NULL)
				ITERATIONS = DEFAULT_ITERATIONS;
			else
				{
				int temp = atoi(pch);
				if(temp < DEFAULT_ITERATIONS)
					ITERATIONS = DEFAULT_ITERATIONS;
				else
					ITERATIONS = temp;
				}
			break;
			}
		else if(strcmp(pch, ";") == 0)
			{
			part++;
			index = 0;
			}
		else
			{
			population[0][part][index] = atoi(pch);
			index++;
			}
		counter++;
		pch = strtok (NULL, " ");
		}
	if(counter != 172)
		{
		counter = 0;
		stopped[0] = 1;
		evaluations[0] = 0;
		ITERATIONS = DEFAULT_ITERATIONS;
		}
	else
		counter = 1;

	for(i = 0; i < POINTS + 1; i++)
			{
			posOfJ[i] = 0;
			}

	//Main Loop
	while(iterations < ITERATIONS)
		{

		//find where all the numbers are in population[0]
		for(int k = 0; k < PARTITIONS; k++)
			{
			for(int l =0; l < POINTS; l++)
				{
				if(population[0][k][l] == 0)
					break;

				posOfJ[population[0][k][l]] = k;
				}
			}

		int intialStopped = stopped[0];
		//Generate rest of population
		for(i = counter; i < CHROMO_PER_POP; i++)
			{
			int part0 = 0, part1 = 0, part2 = 0, part3 = 0, part4 = 0;
			int O1 = offendingNumbers[i][0], O2 = offendingNumbers[i][1], O3 = offendingNumbers[i][2], O4 = offendingNumbers[i][3];
			for(int j = 1; j < POINTS; j++)
				{
				if(j <= intialStopped)
					{
					int r = GetRand() % 1000;
					if(r < 6)
						{
						r = GetRand() % 10;
						if(r < 3)
							{
							population[i][0][part0] = j;
							part0++;
							}
						else if(r < 5)
							{
							population[i][1][part1] = j;
							part1++;
							}
						else if(r < 7)
							{
							population[i][2][part2] = j;
							part2++;
							}
						else if(r < 9)
							{
							population[i][3][part3] = j;
							part3++;
							}
						else
							{
							population[i][4][part4] = j;
							part4++;
							}
						}
					else if(j == O1 || j == O2 || j == O3 || j == O4)
						{
						int r = GetRand() % 100;
						if(r < 50)
							{
							r = GetRand() % 10;
							if(r < 3)
								{
								population[i][0][part0] = j;
								part0++;
								}
							else if(r < 5)
								{
								population[i][1][part1] = j;
								part1++;
								}
							else if(r < 7)
								{
								population[i][2][part2] = j;
								part2++;
								}
							else if(r < 9)
								{
								population[i][3][part3] = j;
								part3++;
								}
							else
								{
								population[i][4][part4] = j;
								part4++;
								}
							}
						else
							{
							part = posOfJ[j];

							if(part == 0)
								{
								population[i][0][part0] = j;
								part0++;
								}
							else if(part == 1)
								{
								population[i][1][part1] = j;
								part1++;
								}
							else if(part == 2)
								{
								population[i][2][part2] = j;
								part2++;
								}
							else if(part == 3)
								{
								population[i][3][part3] = j;
								part3++;
								}
							else
								{
								population[i][4][part4] = j;
								part4++;
								}
							}
						}
					else
						{

						part = posOfJ[j];

						if(part == 0)
							{
							population[i][0][part0] = j;
							part0++;
							}
						else if(part == 1)
							{
							population[i][1][part1] = j;
							part1++;
							}
						else if(part == 2)
							{
							population[i][2][part2] = j;
							part2++;
							}
						else if(part == 3)
							{
							population[i][3][part3] = j;
							part3++;
							}
						else
							{
							population[i][4][part4] = j;
							part4++;
							}
						}
					}
				else if(j == intialStopped + 1)
					{
					//find j in population[0]
					part = posOfJ[j];

					int temp = i % PARTITIONS;

					if(temp == part)
						temp++;

					temp = temp % PARTITIONS;

					if(temp == 0)
						{
						population[i][0][part0] = j;
						part0++;
						}
					else if(temp == 1)
						{
						population[i][1][part1] = j;
						part1++;
						}
					else if(temp == 2)
						{
						population[i][2][part2] = j;
						part2++;
						}
					else if(temp == 3)
						{
						population[i][3][part3] = j;
						part3++;
						}
					else if(temp == 4)
						{
						population[i][4][part4] = j;
						part4++;
						}

					}
				else
					{
					//place randomly

					int r = GetRand() % 10;
					if(r < 3)
						{
						population[i][0][part0] = j;
						part0++;
						}
					else if(r < 5)
						{
						population[i][1][part1] = j;
						part1++;
						}
					else if(r < 7)
						{
						population[i][2][part2] = j;
						part2++;
						}
					else if(r < 9)
						{
						population[i][3][part3] = j;
						part3++;
						}
					else
						{
						population[i][4][part4] = j;
						part4++;
						}
					}
				}
			}

		//Test pop


		for(i = 0; i <	CHROMO_PER_POP; i++)
			{
			int smallestSum = POINTS + 10;
			int sum = 0, offendCounter = 0;


			for(int j = 0; j < PARTITIONS; j++)
				{
				for(int k = 0; k < POINTS; k++)
					{
					if(population[i][j][k] > smallestSum)
						break;

					for(int l = k; l < POINTS; l++)
						{
						if(population[i][j][l] > smallestSum)
							break;

						sum = population[i][j][l] + population[i][j][k];

						if(sum > smallestSum)
							break;

						for(int s = (l+1); s < POINTS; s++)
							{
							if(population[i][j][s] == 0)
								break;

							if(sum < population[i][j][s])
								break;

							if( sum == population[i][j][s])
								{
								if(offendCounter < 3)
									{
									offendingNumbers[i][offendCounter++] = population[i][j][l];
									offendingNumbers[i][offendCounter++] = population[i][j][k];
									}

								if( sum - 1 < smallestSum)
									smallestSum = (sum - 1);
								break;
								}
							}



						if(smallestSum == sum - 1)
							break;
						}
					}
			}



			stopped[i] = smallestSum;
			evaluations[i] = 64*stopped[i];// + (.015625)*GFunc;
			}

		int fittestStopped = 0;

		for(i = 0; i < CHROMO_PER_POP; i++)
			{
			if(stopped[i] > fittestStopped)
				{
				fittestStopped = stopped[i];
				posOfFittest = i;
				}
			}

		//Check if population is stagnant
		if(abs(lastFittest - evaluations[posOfFittest]) < STAGNANT_LEEWAY)
			{
			stagnantIndex++;
			//stopped[0] -= stagnantIndex;
			}
		else
			{
			stagnantIndex = 0;
			lastFittest = evaluations[posOfFittest];
			}

		if(stagnantIndex > TIME_TO_CHANGE)
			{
			int r = GetRand() % 10000;
			if(fittestStopped > bestStopped || r < 5)
				{
				for(int j = 0; j < PARTITIONS; j++)
					{
					for(int k = 0; k < POINTS; k++)
						{
						bestChromo[j][k] = population[posOfFittest][j][k];
						}
					}

				bestStopped = fittestStopped;
				bestEval = evaluations[posOfFittest];
				}

			for(i = 0; i < CHROMO_PER_POP; i++)
				{
				for(int j = 0; j < PARTITIONS; j++)
					{
					for(int k = 0; k < POINTS; k++)
						{
						if(population[i][j][k] == 0)
							break;

						population[i][j][k] = 0;
						}
					}
				}

			int part0 = 0, part1 = 0, part2 = 0, part3 = 0, part4 = 0;

			for(int j = 1; j < POINTS; j++)
				{
				int r = GetRand() % 10;
				if(r < 3)
					{
					population[0][0][part0] = j;
					part0++;
					}
				else if(r < 5)
					{
					population[0][1][part1] = j;
					part1++;
					}
				else if(r < 7)
					{
					population[0][2][part2] = j;
					part2++;
					}
				else if(r < 9)
					{
					population[0][3][part3] = j;
					part3++;
					}
				else
					{
					population[0][4][part4] = j;
					part4++;
					}
				}
			stagnantIndex = 0;
			iterations++;
			}
		else
			{
			int tempPartition[PARTITIONS][POINTS];

			for(int j = 0; j < PARTITIONS; j++)
				{
				for(int k = 0; k < POINTS; k++)
					{
					tempPartition[j][k] = population[posOfFittest][j][k];
					}
				}

			for(i = 0; i < CHROMO_PER_POP; i++)
				{
				for(int j = 0; j < PARTITIONS; j++)
					{
					for(int k = 0; k < POINTS; k++)
						{
						if(population[i][j][k] == 0)
							break;

						population[i][j][k] = 0;
						}
					}
				}

			for(int j = 0; j < PARTITIONS; j++)
				{
				for(int k = 0; k < POINTS; k++)
					{
					if(tempPartition[j][k] == 0)
						break;

					population[0][j][k] = tempPartition[j][k];
					}
				}

			stopped[0] = stopped[posOfFittest];
			evaluations[0] = evaluations[posOfFittest];
			}
		double fractionDone = (double)iterations/(double)ITERATIONS;
		boinc_fraction_done(fractionDone);
		if(boinc_time_to_checkpoint())
			{
				do_checkpoint(bestChromo, bestStopped, bestEval, ITERATIONS, PARTITIONS, POINTS);
				boinc_checkpoint_completed();
			}
		}

	boinc_resolve_filename(OUTPUT_FILENAME, output_path, sizeof(output_path));

	out.open(output_path, "wb");

	stringstream ss;

	for(int j = 0; j < PARTITIONS; j++)
		{
		for(int k = 0; k < POINTS; k++)
			{
			if(bestChromo[j][k] == 0)
				break;

			ss << bestChromo[j][k] << ' ';
			}

		ss << " ; ";
		}

	ss << bestStopped << ' ' << bestEval << ' ' << ITERATIONS << ' ';
	out.puts(ss.str().c_str());
	out.close();

	boinc_finish(0);
	}

#ifdef _WIN32
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR Args, int WinMode) {
	LPSTR command_line;
	char* argv[100];
	int argc;

	command_line = GetCommandLine();
	argc = parse_command_line( command_line, argv );
	return main(argc, argv);
	}
#endif