/*
Selah Lynch   solution.cc   July 2004 

Class Solution Definitions, see .h file for class description
*/

#include <stdio.h>
#include <math.h>
#include "solution.h" 

/*delete this:*/
#include <mpi.h>

Solution::Solution(int numpntsarg){
  numpoints=numpntsarg;
  order = new int [numpoints];
  SetAsRand();
}


Solution::Solution(Solution& s){

  numpoints=s.numpoints;
  order = new int [numpoints];
  for(int i=0; i<numpoints; i++)
    order[i]=s.order[i];
}


Solution::~Solution(){
  delete [] order;
}


void Solution::SetAsRand(){  

  bool picked[numpoints];
  for(int m=0; m<numpoints; m++) picked[m]=false;
  //this keeps track of not repeating the points you visit

  int steps, index;

  for(int n=0; n<numpoints; n++){
    //n points have been picked and set in order
    //pick the (n+1)th point for the order
    steps = rand()%(numpoints-n);
    index=0;
    //the index is the "point number" that i'm going to
    //put down in the order array
    while(steps!=0 || picked[index]){
      if(!picked[index]) steps--;
      index++;
    }
    order[n]=index;

    picked[index]=true;
  }

}

void Solution::SetAsChild(Solution& mom, Solution& dad){

  int pt, pt1, pt2, temp1, temp2, ch_indx;
  bool picked[numpoints];

  for(int i=0; i<numpoints; i++) picked[i]=false;

  pt1=rand()%numpoints;
  temp1=rand()%(numpoints-1)+1;
  pt2=(pt1 + temp1)%numpoints;

  if(pt1>pt2){
    temp2=pt1; pt1=pt2; pt2=temp2;
  }

  //copy appropriate values to child from mom
  for(ch_indx=pt1; ch_indx<=pt2; ch_indx++) {
    order[ch_indx]=mom.order[ch_indx];
    picked[order[ch_indx]]=true;
  }

  //copy appropriate values to child from dad
  ch_indx=0;
  for(int n=0; n<numpoints; n++){
    if(ch_indx==pt1) ch_indx=pt2+1;
    if(!picked[dad.order[n]]){
      order[ch_indx]=dad.order[n];
     ch_indx++;
    }
  }


  //?? make another technique:
  //take two random nonintersecting sets of numbers
  //that span the set of 0 to <numpoints>

  //combine the order of those into the child

  //THEORY: any set of numbers with a favorable connection
  //is a useful piece of information for the solution
  
}


void Solution::SetAsString(int* intstr){
  check (intstr!=NULL,"intstr must be set for SetasIntstr()");
  for(int i=0; i<numpoints; i++){
    order[i]=intstr[i];
  }
}

void Solution::SetAsEqual(Solution& s){
  check(numpoints==s.numpoints,"Solutions must have same number of points.");
  for(int i=0; i<numpoints; i++){
    order[i]=s.order[i];
  }
}


void Solution::MutateSwt(){

  int pt1,pt2, temp1, temp2;

  pt1=rand()%numpoints;
  temp1=rand()%(numpoints-1)+1;
  pt2=(pt1 + temp1)%numpoints;

  temp2=order[pt1];
  order[pt1]=order[pt2];
  order[pt2]=temp2;

}


void Solution::MutateInv(){

  int pt1,pt2, temp1, temp2, temp3;

  pt1=rand()%numpoints;
  temp1=rand()%(numpoints-1)+1;
  pt2=(pt1 + temp1)%numpoints;

  if(pt1>pt2){
    temp2=pt1; pt1=pt2; pt2=temp2;
  }

  for(int i=0; i<((pt2-pt1+1)/2); i++){
    temp3 = order[pt1+i];
    order[pt1+i] = order[pt2-i];
    order[pt2-i] = temp3;
  }

}


void Solution::MutateRot(){

  int incr, *temparr;
  incr=rand()%(numpoints-1)+1;
  temparr=new int [incr];

  for(int i=0; i<incr; i++)
    temparr[i]=order[(numpoints-incr)+i];

  for(int ii=0; ii<numpoints-incr; ii++){
    order[numpoints-1-ii] = order[(numpoints-incr)-1-ii];
  }

  for(int iii=0; iii<incr; iii++)
    order[iii]=temparr[iii];

  delete temparr;
}


void Solution::Display(ostream& o){

    for(int i=0; i<numpoints-1; i++) o<<order[i]<<" ";
    o<<order[numpoints-1];

}

void Solution::SpitOutOrder(int* intstr){
  check(intstr!=NULL, "Integer pointer must have space allocated");
  for(int i=0; i<numpoints; i++){
    intstr[i]=order[i];
  }
}

double Solution::GetDist(Problem& p){
  //printf("Solution numpoints=%d, Problem numpoints=%d\n",numpoints, p.GetNumPoints());
  check(numpoints==p.GetNumPoints(),"Invalid Problem-Solution combination");

  double meh=0;  //find distance

  double deltaY, deltaX, sqrdist, distseg;
  int X=0, Y=1, pt1,pt2;

  for(int i=1; i<numpoints; i++){
    pt1=order[i-1];
    pt2=order[i];

    deltaX=p.GetX(pt1)-p.GetX(pt2);
    deltaY=p.GetY(pt1)-p.GetY(pt2);

    distseg= sqrt(deltaY*deltaY + deltaX*deltaX);

    meh+=distseg;
  }

  return meh;

}


void Solution::check(bool b, char* mess){
  if(!b) {
    printf("\n\nERROR[Solution] - %s \n\n\n", mess);
    exit(0);
  }
}


/*
////Functions from old version for cutting and pasting

void Solution::SetDistance(){

  double meh=0;  //find distance

  double deltaY, deltaX, sqrdist, distseg;
  int X=0, Y=1, pt1,pt2;

  for(int i=1; i<numpoints; i++){
    pt1=order[i-1];
    pt2=order[i];

    deltaY = pointset[pt1][X]-pointset[pt2][X];
    deltaX = pointset[pt1][Y]-pointset[pt2][Y];

    distseg= sqrt(deltaY*deltaY + deltaX*deltaX);

    meh+=distseg;
  }

  dist = meh;
  dist_set = true;
 

}
void Solution::SpitOutOrder(int* intptr){
  check(is_set,"Solution order must be set!");
  check(intptr!=NULL, "Integer pointer must have space allocated");
    for(int i=0; i<numpoints; i++){
      intptr[i]=order[i];
    }
}

*/




