
import java.io.*;
import java.util.*;

public class NYCTBlackBoxGA
{
  public int popsize;
  public double[] fitnesses;
  public NYCTBlackBoxGA(int pop_size_input)
  {
	  popsize=pop_size_input;
	  fitnesses = new double[popsize];
  }

  private void writeFile(boolean array[][])
  {
    try
    {
      PrintStream output = new PrintStream(new FileOutputStream("input.txt"));
      for(int j=0; j<popsize;j++)
         {
		   for (int i = 0;i < 84;i++)
			   output.print((array[i][j])?(1):(0));
           output.println();
	      }
	  output.println();
      output.flush();
      output.close();
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
  }

  private double readFile()
  {
    double answer = 0;

    try
    {
      BufferedReader input = new BufferedReader(new FileReader("output.txt"));
      String s = input.readLine();
      if (s != null) answer = (new Double(s)).doubleValue();
      input.close();
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

    return answer;
  }


private void readFileMultiple()
  {
   String s;
   int i = 0;

   try
    {
      BufferedReader input = new BufferedReader(new FileReader("output.txt"));
      s = input.readLine();
      while(i< popsize && s != null)
         {
		   fitnesses[i++] = (new Double(s)).doubleValue();
		   s = input.readLine();
	      }
      input.close();
    }
    catch (Exception e)   {e.printStackTrace();}
  }

  public double objective(boolean chromosomes[][])
  {
    writeFile(chromosomes);
    try
    {
//      System.out.println(Runtime.getRuntime().exec("command.com /c pipeBB.exe").waitFor());
      Runtime.getRuntime().exec("pipeBB.exe").waitFor();
    }
    catch (Exception e)
    {
      System.out.println("Error running NYCTBlackBox.exe");
    }
    return readFile();
  }

  public static void main(String args[]) throws Exception
  {
	final int CHROM_LENGTH = 84;
	final int POPSIZE= 1000;

	final long RANDOM_SEED = 18675309;
	Random randomizer= new Random(RANDOM_SEED);

    final int MAX_NUM_GENS = 500;    //   SIMPLE GA PARAMETERS
    final double PROB_CROSSOVER= 1.0;   //  for each two parents, prob. children will be xover of parents
    final double PROB_MUTATE = 0.0;    //  bit-wise prob. of bit-flip
    final int tourn_size = 2;



	double worst, best, avg;   //  Run stats


	int gen_num = 0;
	int competitor_1;
	int competitor_2;
	int winner;

	int parent_1, parent_2;
	int crossover_pt_1, crossover_pt_2;
	int temp;

	//  VARIABLES FOR REORDERING DECISION VARIABLES on chromosome
	boolean temp_bit;
	final int START_SWAP_SECTION = 0;   //  first bit position of sect. to be swapped
	final int END_SWAP_SECTION = 0;     //  last bi pos. of sect. to be swapped
	final int OFFSET_SWAP_SECTION = 0;  //  num of bits between two sections to be swapped

   //  Open files for writing fitness stats each generation
    PrintStream best_of_gen_file = new PrintStream(new FileOutputStream("best_of_gen.txt"));
    PrintStream avg_of_gen_file = new PrintStream(new FileOutputStream("avg_of_gen.txt"));
    PrintStream worst_of_gen_file = new PrintStream(new FileOutputStream("worst_of_gen.txt"));

    //  Create BB simulator.  Create chrom array.
    NYCTBlackBoxGA nycBB = new NYCTBlackBoxGA(POPSIZE);
    boolean pop[][]= new boolean[CHROM_LENGTH][nycBB.popsize];    //  Current pop of bit string chroms


    //  Generate initial pop. randomly
    for(int j=0; j<nycBB.popsize;j++)
      for (int i = 0;i < CHROM_LENGTH;i++) pop[i][j] = (randomizer.nextBoolean());


    //  Generation loop
    while(gen_num < MAX_NUM_GENS)
       {

		   //  SWAP
		      for(int j = 0; j < nycBB.popsize; j++)
		       {
		          for(int i = START_SWAP_SECTION; i< END_SWAP_SECTION; i++)
		              {
						  temp_bit = pop[i][j];
						  pop[i][j] = pop[i+OFFSET_SWAP_SECTION][j];
						  pop[i+OFFSET_SWAP_SECTION][j] = temp_bit;
				       }
			   }

		 // evaluate population
           nycBB.objective(pop);
		   nycBB.readFileMultiple();


		   //  UNSWAP
		      for(int j = 0; j < nycBB.popsize; j++)
		       {
		          for(int i = START_SWAP_SECTION; i< END_SWAP_SECTION; i++)
		              {
						  temp_bit = pop[i][j];
						  pop[i][j] = pop[i+OFFSET_SWAP_SECTION][j];
						  pop[i+OFFSET_SWAP_SECTION][j] = temp_bit;
				       }
			   }

         //  Print population to console

/*		   System.out.print("pop = ");
		   for(int j=0;j<nycBB.popsize;j++)
			 {
				 for (int i = 0;i < CHROM_LENGTH;i++) System.out.print("" + ((pop[i][j])?("1"):("0")));
		         System.out.println();
			 }
*/		   System.out.println();

         //  Compute stats on pop. and print

           worst = nycBB.fitnesses[0];
           best = worst;
           avg = 0.0;

		   for(int j=0;j<nycBB.popsize;j++)
			  {
//				  System.out.println("" + nycBB.fitnesses[j]);

			      if(nycBB.fitnesses[j] < best) best = nycBB.fitnesses[j];
			      if(nycBB.fitnesses[j] > worst) worst = nycBB.fitnesses[j];
			      avg += nycBB.fitnesses[j];
			  }
		   avg = avg/POPSIZE;
		   System.out.println("------------" + gen_num +"---------------------");
		   System.out.println("Best design in pop:     " + best);
		   System.out.println("Avg. cost of designs:   " + avg);
		   System.out.println("Worst design in pop:    " + worst);
		   System.out.println();

           //   Print fitness stats to fitness stats files

		   best_of_gen_file.println(best);
		   avg_of_gen_file.println(avg);
		   worst_of_gen_file.println(worst);

		   boolean new_pop[][] = new boolean[CHROM_LENGTH][nycBB.popsize];

          //  Selection
           for(int j = 0; j < nycBB.popsize; j++)
              {
				  competitor_1 = randomizer.nextInt(nycBB.popsize);
				  competitor_2 = randomizer.nextInt(nycBB.popsize);

				  if(1.0/nycBB.fitnesses[competitor_1] > 1.0/nycBB.fitnesses[competitor_2])
				     winner = competitor_1;
				     else winner = competitor_2;

				  for(int i = 0; i < CHROM_LENGTH; i++)
				     new_pop[i][j] = pop[i][winner];
			  }

           pop = new_pop;



		   // CROSSOVER  (two point)

           if(PROB_CROSSOVER > 0.0)  //  if crossover turned off, skip it!
           {
		     new_pop = new boolean[CHROM_LENGTH][nycBB.popsize];

             for(int j = 0; j < nycBB.popsize; j+=2)
              {
				  parent_1 = randomizer.nextInt(nycBB.popsize);
				  parent_2 = randomizer.nextInt(nycBB.popsize);

                  if(randomizer.nextDouble() > PROB_CROSSOVER)
                    {
				      crossover_pt_1 = CHROM_LENGTH;
					  crossover_pt_2 = CHROM_LENGTH;
				    }
				    else
				      {
					    crossover_pt_1 = randomizer.nextInt(CHROM_LENGTH);
				        crossover_pt_2 = randomizer.nextInt(CHROM_LENGTH);
				        if(crossover_pt_2 < crossover_pt_1)
						  {
							 temp = crossover_pt_1;
							 crossover_pt_1 = crossover_pt_2;
							 crossover_pt_2 = temp;
					       }
					  }



				  for(int i=0; i < crossover_pt_1; i++)
				      {
						  new_pop[i][j]   = pop[i][parent_1];
						  new_pop[i][j+1] = pop[i][parent_2];
					  }
				  for(int i=crossover_pt_1; i < crossover_pt_2; i++)
				      {
						  new_pop[i][j]   = pop[i][parent_2];
						  new_pop[i][j+1] = pop[i][parent_1];
					  }
				  for(int i=crossover_pt_2; i < CHROM_LENGTH; i++)
				      {
						  new_pop[i][j]   = pop[i][parent_1];
						  new_pop[i][j+1] = pop[i][parent_2];
					  }
			    }
              pop = new_pop;
		    }  //   END CROSSOVER


		   // MUTATION
          if(PROB_MUTATE > 0.0)  // if mutation turned off, skip this part
           {
		     new_pop = new boolean[CHROM_LENGTH][nycBB.popsize];

             for(int j = 0; j < nycBB.popsize; j++)   // For each indiv.
				  for(int i=0; i<CHROM_LENGTH; i++)   // For each bit...
				      if(randomizer.nextDouble() > PROB_MUTATE)  // bit-wise prob. of mutation
				        new_pop[i][j] = pop[i][j];
				        else new_pop[i][j] = ! pop[i][j];
            pop = new_pop;
		   }   //  END MUTATION

        gen_num++;

	   }   //  END OF MAIN GENERATION while LOOP


   //  Close fitness stats files

		  best_of_gen_file.println();
       	  avg_of_gen_file.flush();
      	  worst_of_gen_file.close();

    System.exit(0);    // end of program, end of run
  }
}















