int
main(int argc, char* argv[])
{
    output = fopen("final", "wb");

    argc--;
    path = malloc(MAX_PATH * sizeof(char));
    isMaster = 1;

    //only works with number of files that are a power of two!
    if(!isPowerOfTwo(argc))
    {
        printf("# of args(%i) not power of 2\n", argc);
        return 0;
    }

    filenames = malloc(sizeof(char*) * argc);
    //stores files into global array
    for(int i = 0; i < argc; i++)
    {
        filenames[i] = argv[i + 1];
    }

    //number of levels in the tree, discluding the master node
    max_levels = (int)(log(argc) / log(2));
    spawnChildren(max_levels);

    free(filenames);
    fclose(output);
    sleep(1);
    return 0;
}
/* Recursively spawns 2 children per parent
 * Determines who is whom(master, parents, children) */
void
spawnChildren(int levels)
{
    //no more levels underneath you means you are a leaf process
    if(levels == 0)
    {
        readSort();
        return;
    }
     
    int len = strlen(path);

    if(isMaster)
       pipe(fd[UP]);

    pipe(fd[LEFT]);
    pipe(fd[RIGHT]);

    //spawns 2 children at a single parent, prevents child
    //having another child within the fork'd process
    int pid = fork();
    //parent
    if(pid > 0)
    {
        int pid2 = fork();
        //child
        if(pid2 == 0)
        {
            if(!isMaster)
            {
                if(levels-1)
                   printf("Parent(%d) spawned process(%d).\n", getppid(), getpid());
                else
                   printf("Parent(%d) spawned leaf process(%d).\n", getppid(), getpid()); 
            }
            else
                printf("Master(%d) spawned process(%d).\n", getppid(), getpid());
            isMaster = 0;
            dup2(fd[RIGHT][WRITE], fd[UP][WRITE]);
            close(fd[LEFT][WRITE]);
            close(fd[RIGHT][WRITE]);
            //record path
            path[len] = '1';
            path[len+1] = '\0';
            spawnChildren(levels-1);
            return;
        }
    }
    //child
    else
    {
        if(!isMaster)
        {
            if(levels-1)
                printf("Parent(%d) spawned process(%d).\n", getppid(), getpid());
            else
                printf("Parent(%d) spawned leaf process(%d).\n", getppid(), getpid());
        }
        else
            printf("Master(%d) spawned process(%d).\n", getppid(), getpid());
        isMaster = 0;
        dup2(fd[LEFT][WRITE], fd[UP][WRITE]);
        close(fd[RIGHT][WRITE]);
        close(fd[LEFT][WRITE]);
        //record path
        path[len] = '0';
        path[len+1] = '\0';
        spawnChildren(levels-1);
        return;
    }

    //parent or master
    if(levels > 0)
    {
       if(isMaster)
           close(fd[UP][WRITE]);
       close(fd[UP][READ]);
       close(fd[LEFT][WRITE]);
       close(fd[RIGHT][WRITE]);

       //numbers to be compared
       int num[2];
       //status of reading from buffer
       int status[2];
       //which side is finished
       int finished[2];

       //initial values
       status[LEFT] = read(fd[LEFT][READ], &num[LEFT], sizeof(int));
       if(status[LEFT] != sizeof(int))
           finished[LEFT] = 1;
       else
           finished[LEFT] = 0;

       status[RIGHT] = read(fd[RIGHT][READ], &num[RIGHT], sizeof(int));
       if(status[RIGHT] != sizeof(int))
           finished[RIGHT] = 1;
       else
           finished[RIGHT] = 0;
       
       while(finished[LEFT] == 0 || finished[RIGHT] == 0)
       {
           if(!finished[LEFT] && (num[LEFT] < num[RIGHT] || finished[RIGHT]))
           {
               //if not at top keep sending up
               if(!isMaster)
                  write(fd[UP][WRITE], &num[LEFT], sizeof(int));
               //otherwise you're the master and write to file
               else
                  fprintf(output, "%u\n", num[LEFT]);
               status[LEFT] = read(fd[LEFT][READ], &num[LEFT], sizeof(int));
               //no more bytes to read
               if(status[LEFT] != sizeof(int))
               {
                  close(fd[LEFT][READ]);
                  finished[LEFT] = 1;
               }
           }
           else if(!finished[RIGHT] && (num[RIGHT] <= num[LEFT] || finished[LEFT]))
           {
               //if not at top keep sending up
               if(!isMaster)
                  write(fd[UP][WRITE], &num[RIGHT], sizeof(int));
               //otherwise you're the master and write to file
               else
                  fprintf(output, "%u\n", num[RIGHT]);
               status[RIGHT] = read(fd[RIGHT][READ], &num[RIGHT], sizeof(int));
               //no more bytes to read
               if(status[RIGHT] != sizeof(int))
               {
                  close(fd[RIGHT][READ]);
                  finished[RIGHT] = 1;
               }
           }
       }
       close(fd[UP][WRITE]);
       if(isMaster)
           printf("Wrote sorted file to 'final'.\n");
    }
}
bool NaiveAlgorithm::tick()
{
    cpFloat bestFitness = -INFINITY; // we want zero fitness
    cpFloat worstFitness = INFINITY;
    
    cpFloat lastBestFitness = bestIndividual ? bestIndividual->fitness : bestFitness;

    std::vector<SystemInfo *>nextGen = spawnChildren();
    
    // add old population
    for (size_t popIter = 0; popIter <population.size(); popIter++) {
        // reset the individual... by copying!
        SystemInfo *individual = population[popIter];
        MachineSystem *original = individual->system;
        MachineSystem *copy = new MachineSystem(*original);
        individual->system = copy;
        delete original;
        
        nextGen.push_back(individual);
    }
    
    for (size_t popIter = 0; popIter <nextGen.size(); popIter++) {
        SystemInfo *individual = nextGen[popIter];
 
        stepSystem(individual);
        individual->fitness = evaluateSystem(individual);
    }
    
   
    // cut the population back down to size
    std::sort(nextGen.begin(), nextGen.end(), isMoreFit);
    
    bestIndividual = nextGen.front();
    bestFitness = bestIndividual->fitness;
    
    worstFitness = nextGen.back()->fitness;
    
    std::vector<SystemInfo *>::iterator deleteIt = nextGen.begin()+population.size();
    while (deleteIt != nextGen.end()) {
        SystemInfo *unfit = *deleteIt;
        assert(unfit != bestIndividual);
        delete  unfit;
        deleteIt = nextGen.erase(deleteIt);
    }
    
    if (bestFitness > allTimeBestFitness)
        allTimeBestFitness = bestFitness;
    
    
    assert(nextGen.size() == population.size());
    
    population = nextGen;
    
    fprintf(stderr, "BEST FITNESS: %f \n", bestFitness);
    fprintf(stderr, "WORST FITNESS: %f \n", worstFitness);
    
    if (lastBestFitness == bestFitness)
        stagnantGenerations++;
    else
        stagnantGenerations = 0;
    
    bool stop =  (generations >= maxGenerations) || goodEnoughFitness(bestFitness) || (stagnantGenerations >= maxStagnation);
    
    generations++;
    logPopulationStatistics();
    
    if (stop) {
        fprintf(stderr, "ALL TIME BEST FITNESS: %f\n", allTimeBestFitness);
    }
    return  stop;
}