/*
 * Group9Team4.java
 *
 * Created on November 22, 2004, 8:51 PM
 */

// TODO - shudlanechande front to be modified so that it says if i m drafting or not

// changed made....shud lane change added to the end, energy considered,sorted considered in right way
// players are sorted each time now
package Olympics.g9;
import Olympics.*;
import java.io.Serializable;
import java.util.*;
import java.awt.Color;

public class Group9Team1 implements IFCPlayer {

    Olympics            _olympics;
    static Random       _random;
    static final String _CNAME = "Catch me if u can!!!";
    int ridersPerTeam, raceLength, numberOfLanes, teamNumber, initialEnergy, numOfTeams;
    boolean [] alive;
    static final boolean INDEPENDENT = true;
    static final boolean SUPPORT = false;
    boolean mode = INDEPENDENT;
    boolean sprint = true;
    boolean[] midLane;
    int stayPutCount = 0, speedCount = 0;
    int sorted[];
    boolean playersSorted = false;
    double initialVelocity, optimalVelocity;
    RiderInfo[] info; 
    double[] accs;
    int[] lanes; 
    boolean front, back, middle, draft;
    public void register(Olympics __olympics) throws Exception {
        _olympics = __olympics;
        ridersPerTeam = _olympics.R();
        raceLength = _olympics.D();
        numberOfLanes = _olympics.L();
        numOfTeams = _olympics.numTeams();
        teamNumber = _olympics.indexOf(this);
	initialEnergy = _olympics.E();
        alive = new boolean[ridersPerTeam];
	_random = new Random();
        midLane = new boolean[ridersPerTeam];
        for (int i = 0; i < ridersPerTeam; i++) {
            midLane[i] = false;
        }
        sorted = new int[ridersPerTeam];
        initAlive(ridersPerTeam);
        Random rand = new Random();
       // double maxVelocity = 
       // double maxVelocity =  Math.pow( (initialEnergy/raceLength), (double)2/(double)3);
        double maxVelocity = Math.pow((initialEnergy)/(raceLength)*(10.0/7.0 * (1 - Math.pow(.3, ridersPerTeam))), 2.0 / 3.0);
        initialVelocity = maxVelocity;
        //initialVelocity = rand.nextInt((int)Math.ceil(maxVelocity)) + maxVelocity/2; // choose a random number between 2 n maxVel
        info = _olympics.TeamStatus(_olympics.indexOf(this));
        accs = new double[ridersPerTeam];
	lanes = new int[ridersPerTeam];
        double optimalVelocity = Math.ceil(Math.pow((initialEnergy)/(raceLength)*(10.0/7.0 * (1 - Math.pow(.3, ridersPerTeam))), 2.0 / 3.0));
    }

    public String name() throws Exception {
        return _CNAME;
    }

    public Color color() throws Exception {
        return new Color(0.855f, 0.438f, 0.855f);
    }

    public boolean interactive() throws Exception {
        return false;
    }

    public int getCurrMidPoint(RiderInfo[] info) {
        int minLane = 9999;
        int maxLane = -1;
        int midpoint;
        for(int a = 0; a < info.length; a++){
            if( info[a].lane() > maxLane){
                maxLane = info[a].lane();
            }
            if( info[a].lane() < minLane){
                minLane = info[a].lane();
            }
        }
        
       midpoint = (int)Math.floor((double)(maxLane+minLane)/2);        
       return(midpoint);
    }
    
    public double findPosMaxEnergy(RiderInfo[] info, double maxEnergy){
        double tmpMaxPos = 0.0;
        for(int b = 0; b < info.length; b++){
            if( info[b].energy() == maxEnergy) {
                tmpMaxPos = info[b].position();
	    }
        }
        return(tmpMaxPos);
    }
    
    public double findMaxEnergy(RiderInfo[] info){
        double maxEnergy = -99999999;
        double tmpMaxPos;
        for(int b = 0; b < info.length; b++){
            if( info[b].energy() > 0 && info[b].energy() > maxEnergy){
		maxEnergy = info[b].energy();
                tmpMaxPos = info[b].position();
	    }
        }
        return(maxEnergy);
    }
    
    public double findMinEnergy(RiderInfo[] info){
        double minEnergy = 99999999;
        double tmpMinPos;
        for(int b = 0; b < info.length; b++){
            if( info[b].energy() < minEnergy){
		minEnergy = info[b].energy();
                tmpMinPos = info[b].position();
	    }
        }
        return(minEnergy);
    }
    
    public void PerformFinalSprint(RiderInfo[] info, boolean [] sprint) {
   
        for (int i = 0; i < info.length; i++) {
            sprint[i] = false;
            if (info[i].energy() > 0) // if ith player is alive
                if (info[i].energy() > Math.pow(25.0,2.5)*(raceLength - info[i].position())){
                    sprint[i] = true;
                }
        }
    }
    
    public boolean canIMoveAtFinalVel (RiderInfo[] info, int i) {
        boolean[] sprint = new boolean[info.length];
        PerformFinalSprint(info,sprint);
        if (sprint[i]) return(true);
        else return(false);
    }
    
    public void initAlive(int num) {
        for(int i=0; i < num; i++) {
            alive[i] = true;
        }
        
    }
    
    public int howManyAlive(int num) {
        int count = 0;
        for(int i=0; i < num; i++) {
            if (alive[i]) count++;
        }
        return(count);
    }
    
    // call this function after each iteration
    public void updateAlive(RiderInfo[] info) {
        for(int i=0; i < info.length; i++) {
            if (info[i].energy() < 0) {
                alive[i] = false;
             //   for (int l = 0; l < info.length; l++) {
               //     if (sorted[l] == i) sorted[l] = -1;
               // }
            }
        }
    }
    
   public boolean areTheyInLine(RiderInfo[] info) {
       int midpoint = 0;
        for(int i = 0; i < info.length; i++) {
            if (info[i].energy() > 0) {
                midpoint = info[i].lane();     
                break;
            }
        }
        for (int i = 0; i < info.length; i++) {
            if (info[i].energy() > 0) {
                if (info[i].lane() != midpoint) return(false);
            }
        }
        return(true);
   }
   
   boolean isLagging (int i, RiderInfo[] info){
         boolean lagging = false;
         int totalDis = 0; // to check if they are back to back
         int totalAhead = 0; // get my positio
         for(int j =0; j < info.length; j++) {
             if (i != j) {
                  if ((info[j].energy() > 0)&&(info[i].energy() > 0))
                    if ((info[j].position() - info[i].position()) > 0){
                          totalAhead++;
                          totalDis+= info[j].position() - info[i].position();                                  
                    }
             }
         }    
         //System.out.println("Inside the function lagging ");
         //System.out.println("Player number "+i);
         //System.out.println("TotalDistance "+ totalDis);
         //System.out.println("TotalAhead "+totalAhead);
         switch (totalAhead) {
             /**** Change made here is acc changed to take into account the change in distance**/
             case 3 : if (totalDis > 12) 
                      lagging = true;  
                      break;  
             case 2 : if (totalDis > 6) 
                      lagging = true;
                      break;  
             case 1 : if (totalDis > 2) 
                      lagging = true;
                      break;
             case 0 : 
                      lagging = false;
                      break;
         }

         return(lagging);
    }
   
   public boolean isLaneFree(int laneNumber) throws Exception { // we pass the lane number in direction of the target
            RiderInfo riderinfo;
            boolean free = true;
            for (int i =0; i < numOfTeams; i++) {    
                if (i != teamNumber)
                for(int j=0; j < ridersPerTeam; j++ ) {
                    riderinfo = _olympics.TeamStatus(i,j);
                    if (riderinfo.energy() > 0)
                    for (int k = 0; k < info.length; k++) {
                        if (info[k].energy() > 0)
                            if (riderinfo.position() ==  info[k].position()) { // if they have same positions
                                if (riderinfo.lane() == laneNumber) return (false); // if he is in the desired lane
                                else continue;
                            }
                    }
                }
            }
            return(free);
   }
   
   public int decideLane(RiderInfo[] info) throws Exception {
        boolean right = true; // try moving towards right
        boolean left = true;
        RiderInfo riderinfo;
        // check which lane is not occupied and move right left accordingly
        
            for (int i =0; i < numOfTeams; i++) {    
                if (i != teamNumber)
                for(int j=0; j < ridersPerTeam; j++ ) {
                    riderinfo = _olympics.TeamStatus(i,j);
                    if (riderinfo.energy() > 0)
                    for (int k = 0; k < info.length; k++) {
                        if (info[k].energy() > 0)
                        if (riderinfo.position() ==  info[k].position()) { // if they have same positions
                            if (right) { // if right is still available                            
                                if (((riderinfo.lane() - info[k].lane()) == 1)||(info[k].lane() == numberOfLanes -1)) { // if he is to my right, or i m in the rightmost lane
                                    right = false;
                                }
                            }
                            if (left) { // if left is still availabe
                                if (((riderinfo.lane() - info[k].lane()) == -1)||(info[k].lane() == 0) ){ // if he is to my left or I am i the left most lane
                                    left = false;
                                }
                            }
                            if (!right && !left) break; //since both right n left are occupied
                        }
                        else continue;
                    }
                    if (left || right) continue;
                    else break;
            }
             if (left || right) continue;
             else break;
        }
        //System.out.println("In decide lane left "+left+" right ="+right);
        if(right && left) { // if both right n left are available
            Random rand = new Random();
            int p = rand.nextInt(2);
            if (p == 1) return (_CMOVERIGHT);
            else return(_CMOVELEFT);
        }
        
        if (right) return (_CMOVERIGHT);
        else if (left) return(_CMOVELEFT);
        return(_CSTAYPUT);
   }
   
   public boolean ShouldChangeLaneForBack (RiderInfo myInfo) throws Exception{
       RiderInfo info;
        // check if there is so other rider from some other tema in between the lane
        for (int i =0; i < numOfTeams; i++) {
            if (i != teamNumber) // if its not my team
            for(int j=0; j < ridersPerTeam; j++ ) {
                info = _olympics.TeamStatus(i,j);
                if (info.energy() > 0)
                if (myInfo.lane() != info.lane()) continue; // they are in different lanes
                else { // if they are in the same lane 
                    double diff = info.position() - myInfo.position();
                    if (diff > 0) continue; // if he is ahead of me..
                    else { // he is behind me
                        
                        if (myInfo.position() - info.position() <= 5) { // if we are back to back
                            if (info.speed() < myInfo.speed())  return(false); // i m moving fast 
                            else if ((info.speed() > myInfo.speed())) continue; // block him
                            else return(true); // his speed is equal to mine...he is drafting
                        }
                    }
                            
                }
             }                    
           
       }     
       return(false);
   }
   
   // if this returns false it shud say if it is ideal case
   public boolean ShouldChangeLaneForFront(RiderInfo myInfo, double optimalVelocity) throws Exception {
       RiderInfo info;
       int count = 0;
        // check if there is so other rider from some other tema in between the lane
       //System.out.println("Shud change lane..called");
        for (int i =0; i < numOfTeams; i++) {
            if (i != teamNumber) // if its not my team
            for(int j=0; j < ridersPerTeam; j++ ) {
                info = _olympics.TeamStatus(i,j);
                if (info.energy() > 0)
                    //System.out.println("My lane is "+ myInfo.lane());
                    //System.out.println("Info lane is "+ info.lane());
                if (myInfo.lane() != info.lane()) continue; // they are in different lanes
                else { // if they are in the same lane 
                    count++;
                    //System.out.println("Came in here "+count);
                    //System.out.println(" Info position" +info.position() + "info.speed() "+ info.speed() + "my position "+ myInfo.position()+ "My info speed "+myInfo.speed() + "optimal velocity "+optimalVelocity);
                    double diff = info.position() - myInfo.position();
                    if (diff < 0) continue; // if he is behind me ... 
                    else { // he is ahead of me
                      
                        if (info.position() - myInfo.position() <= 5) { // if we are back to back
                            //System.out.println("Deep In the lane change method");
                            
                            if (info.speed() < optimalVelocity)  return(true); // if his speed is less than my curr optimal vel
                            else continue; // his speed is greater than equal to my opt vel..if equal ideal, if greater np
                        }
                    }
                            
                }
             }                    
           
       }     
       return(false);
   }
   
   
   /*public boolean ShouldChangeLaneForDraft(RiderInfo myInfo, double optimalVelocity, int [] lanes) throws Exception {
       RiderInfo info;
       
        // check if there is so other rider from some other tema in between the lane
       //System.out.println("Shud change lane..called");
        for (int i =0; i < numOfTeams; i++) {
            if (i != teamNumber) // if its not my team
            for(int j=0; j < ridersPerTeam; j++ ) {
                info = _olympics.TeamStatus(i,j);
                if (info.energy() > 0)
                    
                    
                    double diff = info.position() - myInfo.position();
                    if (diff < 0) continue; // if he is behind me ... 
                    else { // he is ahead of me
                      
                        if (info.position() - myInfo.position() <= 5) { // if we are back to back
                            //System.out.println("Deep In the lane change method");
                           // further modification - try n accelearate 
                            if (info.speed() > optimalVelocity)  continue; // if his speed is > than my curr optimal vel no point chasing him
                            else { // decide to change lanes if needed
                                
                                if (info.lane() != myInfo.lane()) { // different lanes
                                        if (info.lane() > myInfo.lane()) { 
                                            boolean free = isLaneFree(myInfo.lane()+1);
                                            if (free){
                                                for(int l = 0; l < ridersPerTeam; l++)
                                                    lanes[l] = _CMOVERIGHT;
                                                return(true);
                                            }
                                            else continue;       
                                        }
                                        else {
                                            
                                            boolean free =  isLaneFree(myInfo.lane());
                                            if (free) {
                                                for(int l = 0; l < ridersPerTeam; l++)
                                                    lanes[l] = _CMOVELEFT;
                                                return(true);
                                            }
                                            else continue;
                                            
                                        }
                                }
                     
                            }
                        }
                    }
                            
                
             }                    
           
       }     
       return(false);
   }*/
   
   public boolean ShouldChangeLaneForMiddle(RiderInfo myInfo, RiderInfo frontInfo) throws Exception {        
        RiderInfo info;
        // check if there is so other rider from some other tema in between the lane
        for (int i =0; i < numOfTeams; i++) {
            if (i != teamNumber) // if its not my team
            for(int j=0; j < ridersPerTeam; j++ ) {
                info = _olympics.TeamStatus(i,j);
                if (info.energy() > 0)
                if (myInfo.lane() != info.lane()) continue; // they are in different lanes
                else { // if they are in the same lane 
                    double diff = info.position() - myInfo.position();
                    if (diff < 0) continue; // if he is behind me ... 
                    else { // he is ahead of me
                        // if he is in between me and the guy in the front
                        if (myInfo.position() < info.position() && info.position() < frontInfo.position()) {
                            return(true); 
                        }
                    }
                            
                }
             }                    
           
       }     
       return(false);
    }
   
    public void MoveNFormALane(RiderInfo[] info, int[] lanes, double[] accs, int midpoint) {
       
       
       //double minEnergy = initialEnergy;
        
        //double minEnergy,maxEnergy;
        //minEnergy = findMinEnergy(info);
        //maxEnergy = findMaxEnergy(info);
            int i;
            for(int b = 0; b < info.length; b++){
                if( info[b].lane() > midpoint){
                     lanes[b] = _CMOVELEFT;
                         for(i = 0; i < info.length; i++) {
                            if (i != b) {
                                if (((info[b].lane() - info[i].lane()) == 1)&&(info[i].position() == info[b].position())) { // i fall back
                                    if (info[b].speed() > 3.0)
                                        accs[b] = -1.0;
                                    else accs[b] = 0.0;
                                    break;
                                } 
                            }  
                         }
                         if (i == info.length) { // if there wasn't a break in prev loop
                             if (info[b].speed () >= initialVelocity) {
                                 accs[b] = 0.0;
                             }
                             else accs[b] = 1.0;
                         }
                         else { // if there was a break, i shud not accelerate since other guy decelerated for me
                             accs[b] = 0.0;
                         }
                 }
                 else if( info[b].lane() < midpoint){
                           lanes[b] = _CMOVERIGHT;
                           for(i = 0; i < info.length; i++) {
                                if (i != b) {
                                    if (((info[b].lane() - info[i].lane()) == -1)&&(info[i].position() == info[b].position())) { // i fall back
                                        if (info[b].speed() > 3.0)
                                            accs[b] = -1.0;
                                        else accs[b] = 0.0;
                                        break;
                                    } 
                                }  
                           }
                            if (i == info.length) { // if there wasn't a break in prev loop
                                 if (info[b].speed () >= initialVelocity) {
                                     accs[b] = 0.0;
                                 }
                                 else accs[b] = 1.0;
                            }
                            else {
                                accs[b] = 1.0;
                            }
                 }                     
                 else {
                        lanes[b] = _CSTAYPUT;
                        if (info[b].speed() >= initialVelocity) {
                            accs[b] = -1.0;
                        }
                        else {
                            accs[b] = 1.0;
                        }
                }
            }       
        
    }
    
    
    
    public Move move() throws Exception {
        front = back = middle = draft = false;
        Random rand = new Random();
        info = _olympics.TeamStatus(_olympics.indexOf(this));
	
        updateAlive(info); // initialize all of them to alive
        int midpoint = numberOfLanes - 1;
       // System.out.println("Group 9 Initial Velicity = " +initialVelocity);
        //System.out.println("");
      //  System.out.println("My team number "+teamNumber);
        for (int k = 0; k < info.length; k++) {
            if (info[k].energy() > 0) {
                if (info[k].position() > 0.8*raceLength) {
                    //System.out.println("");
                for (int d = 0; d < info.length; d++)   
                    //System.out.println("Rider["+d+"] speed["+info[d].speed()+"] energy remaining["+info[d].energy()+"]"+" position["+info[d].position()+"]");
                 break;
                }
            }
        }
        double  maxEnergy = findMaxEnergy(info);
        double posMax = findPosMaxEnergy(info, maxEnergy);
        int numAlive = howManyAlive(info.length);
        double optimalVelocity = Math.pow((maxEnergy)/(raceLength - posMax)*(10.0/7.0 * (1 - Math.pow(.3, numAlive))), 2.0 / 3.0);
        
        if (numAlive < ridersPerTeam) 
          //  for (int k = 0; k < info.length; k++)
            //    if (info[k].energy() > 0)
              //      optimalVelocity =  Math.floor(Math.pow(info[k].energy()/(raceLength - info[k].position()),(double)2/(double)3));
                       if (numAlive == 1)
                      optimalVelocity =  Math.floor(Math.pow(maxEnergy/(raceLength - posMax + 0.02*(raceLength - posMax)),(double)2/(double)3));
                       else 
                       optimalVelocity = (Math.pow((initialEnergy)/(raceLength)*(10.0/7.0 * (1 - Math.pow(.3, numAlive))), 2.0 / 3.0)); 
   
           // optimalVelocity = Math.pow((initialEnergy)/raceLength * (10.0/7.0 * (1 - Math.pow(.3, numAlive))), 2.0 / 3.0);
            //1)optimalVelocity =  Math.pow( (maxEnergy/(raceLength - posMax)), (double)2/(double)3) + 2;
        //move ahead first n get ahead of everyone
        //System.out.print("Optimal velocity " +optimalVelocity);
        /*while (speedCount < ridersPerTeam) {
            for (int i = 0; i < info.length ; i++) {
                if (info[i].speed() >=  initialVelocity) {
                    speedCount++;
                    accs[i] = 0.0;
                    continue;
                }
                else {
                    accs[i] = 1.0;
                }
            }
            return new Move(accs, lanes);
        
        }*/
        //System.out.println("This is the speed count "+speedCount);
        while (stayPutCount < ridersPerTeam) {
            int[] prevLanes = new int[ridersPerTeam];
            midpoint = getCurrMidPoint(info); 
            for (int i = 0; i < info.length; i++) {
                prevLanes[i] = info[i].lane();
            }
            MoveNFormALane(info, lanes, accs, midpoint);
            for(int i = 0; i < info.length; i++) {
                
                if ((prevLanes[i] == info[i].lane()) && !midLane[i]) { // in case there seems to be a deadlock
                    //System.out.println("Comes in this stupid loop");
                    /*int temp = rand.nextInt(3)+1;
                    switch(temp) { //there seems to be a deadlock
                        case 1 : accs[i] = 0.0;
                               // System.out.println("Comes in this random loop");
                                 break;
                        case 2: accs[i] = 1.0;
                               // System.out.println("Comes in this random loop");
                                break;
                        case 3: accs[i] = -1.0;
                               // System.out.println("Comes in this random loop");
                                break;
                    }*/
                }
                
            }
            for (int b = 0; b < info.length; b++) {
                if ((lanes[b] == _CSTAYPUT)&& !midLane[b]) {
                    stayPutCount++;
                    //System.out.flush();
                    //System.out.println("New stayput count "+stayPutCount);
                    midLane[b] = true;
                }
            }    
                       return new Move(accs, lanes);
        }
        //System.out.println("Got out of this loop");
        // sort according to positions
        //using midLane for the time being
        
        boolean checkLine = areTheyInLine(info);
        
        //System.out.println("CheckLine" + checkLine);
        if (!checkLine) {
           stayPutCount = 0;
           for (int i = 0; i < info.length; i++) {
               midLane[i] = false;
           }
        }
        
        if (!playersSorted) {
            for (int k = 0; k < info.length; k++) {
                double min = raceLength;
                int temp = 0;
                for (int p = 0; p < info.length; p++) {
                    if ((info[p].position() < min) && midLane[p] && info[p].energy() > 0)  {
                        min = info[p].position();
                        temp = p;
                    }
                }
                sorted[k] = temp;
                midLane[temp] = false;
            }
            //playersSorted = true;
        }
        
        for (int m = 0; m < info.length; m++) {
            
            //System.out.println("Sorted " + m + " = " +sorted[m]);
        }
        
        
        if (numAlive > 1) // dont care if one dies
        for (int j= 0 ; j < info.length - 1; j++) {     
                    boolean inLine = true;
                    for (int b = 0; b < info.length; b++){
                        if (!isLagging(sorted[b],info) || info[b].energy() < 0) continue; 
                        else {
                            inLine = false; // still not in line
                            break;
                        }
                    }
                    if (inLine) break;
                    boolean lagging = isLagging(sorted[j],info);
                    //System.out.println("lagging = " +lagging+ " of "+sorted[j]);
                    if (lagging) { // see if there is a gap somewhere
                          //System.out.println("Lagging loop");
                          // think and get this speed later
                          //double avgSpeed = (info[sorted[j]].speed() + info[sorted[j+1]].speed())/2;
                           
                          for (int i = j+1; i < info.length; i++) { // accelerate ,deccelerate the ones in front as needed
                              /*if (i != sorted[j]) {*/
                                  if ((info[sorted[i]].position()+info[sorted[i]].speed()) - (info[sorted[j]].position()+info[sorted[j]].speed()) > 2*(sorted[i] - sorted[j])) { // find out where the gap is
                                      for (int m = 0; m <= i-1; m++) { // accelerate all till that point
                                             accs[sorted[m]] = 1.0; // accelerate j as well as the ones at the back
                                      }
                                      // decelerate the ones beyond that point
                                      for (int k = i; k < info.length; k++ ) {
                                        if (info[sorted[k]].speed() > 5.0) { // substitue optimal velocity here
                                            accs[sorted[k]] = -1.0;
                                        }
                                        else accs[sorted[k]] = 0.0;
                                      }
                                  }
                                  else continue;
                         
                              /*if (info[sorted[i]].speed() > 5.0)
                                accs[sorted[i]] = -1.0; 
                              else
                                  accs[sorted[i]] = 0.0;*/
                          }
                       
                       boolean changeLane = false;
                       for (int m = 0; m < ridersPerTeam; m++) {
                            if ( m ==  numAlive - 1) { // m is the front rider
                                if (info[sorted[m]].energy() > 0)
                                changeLane = ShouldChangeLaneForFront(info[sorted[m]], optimalVelocity);
                                if (changeLane) front = true;    
                            }
                            else {
                                if (info[sorted[m]].energy() > 0 && info[sorted[m+1]].energy() > 0)
                                changeLane = ShouldChangeLaneForMiddle(info[sorted[m]], info[sorted[m+1]]);
                                if (changeLane) middle = true;
                                //System.out.println("Change lane because of the front rider " +changeLane);
                            }
                            if (changeLane) break;
                       }   
                       //System.out.println("Change lane in the lagging loop" + changeLane);
                       
                       if (!changeLane) { // both front n middle did not cause it, check back
                         for (int m = 0; m < ridersPerTeam; m++) {
                             if (m == 0) { // 1st one has to be alive
                                if (info[sorted[m]].energy() > 0)
                                    changeLane = ShouldChangeLaneForBack(info[sorted[m]]);
                                    if (changeLane) back = true;
                             }
                             if (changeLane) break;
                          }     
                       }
                       if (changeLane) { //decide which lane to change to left or right or stayput
                            int temp = decideLane(info); // if temp == stay put, that is blocked frm both sides try to change accs
                            if (temp == _CSTAYPUT) {
                                    if (front || middle ) 
                                    for (int i = 0 ; i <info.length; i++) {
                                         
                                         accs[i] = -1.0;
                                       
                                    }
                                    else if (back)  
                                    for (int i = 0; i < info.length; i++)    {
                                        accs[i] = 1.0; // if it is cos of back or middle
                                    }
                            }
                            for (int t = 0; t < info.length; t++) {
                               lanes[t] = temp;
                            }
                       }
                       
                       return new Move(accs, lanes);
                    }
                    else continue;
        }
        
        //System.out.println("Got out of the final loop");
        //System.out.println("Now everyone moves with optimal velocity");
        
        // incorporate lane changes for blocking players in this part
        for (int b = 0; b < info.length; b++)   {
            if (info[b].energy() > 0) { // if the player is alive
                if (info[b].speed() < optimalVelocity) {
                    accs[b] = 1.0;
                }
                else 
                    if (info[b].speed() > optimalVelocity) {
                        accs[b] = -1.0;
                    }
                    else accs[b] = 0.0;
            }
        }
        boolean changeLane = false;
        for (int m = ridersPerTeam - 1; m >= 0; m--) {
            //System.out.println("Comes here m = "+ m + "numAlive "+(numAlive - 1));
           if ( m ==  numAlive - 1) { // m is the front rider
             //   System.out.println("Comes here m = "+ m + "numAlive "+(numAlive - 1));
                if (info[sorted[m]].energy() > 0)
                    changeLane = ShouldChangeLaneForFront(info[sorted[m]], optimalVelocity);
                    if (changeLane) front = true;
           } // else try for the change lane cos of back
                 
            if (changeLane) break;
         } 
         
        /*if (!front) {
          for (int m = ridersPerTeam - 1; m >= 0; m--) {
            //System.out.println("Comes here m = "+ m + "numAlive "+(numAlive - 1));
           if ( m ==  numAlive - 1) { // m is the front rider
             
                if (info[sorted[m]].energy() > 0)
                    changeLane = ShouldChangeLaneForDraft(info[sorted[m]], optimalVelocity, lanes);
                    if (changeLane) draft = true;
           } // else try for the change lane cos of back
                 
            if (changeLane) break;
         }   
        }*/
        
         if (!front && !draft)  { // front rider did not cause a change, check at back
             for (int m = 0; m < ridersPerTeam; m++) {
                 if (m == 0) { // 1st one has to be alive
                     if (info[sorted[m]].energy() > 0)
                        changeLane = ShouldChangeLaneForBack(info[sorted[m]]);
                        if (changeLane) back = true;
                 }
                 if (changeLane) break;
             }
             
         }
        
         //System.out.println("Comes near the lane changing loop " + changeLane);                
         if (changeLane && !draft) { //decide which lane to change to left or right or stayput
           //System.out.println("Change lane" + changeLane);
           int temp = decideLane(info); // if temp == stay put, that is blocked frm both sides try to change accs
           if (temp == _CSTAYPUT) { // if stuck decelerate, if its cos of guy at the back              
               if (front) 
                  for (int i = 0 ; i <info.length; i++){
                      accs[i] = -1.0;
                                       
                  }
               else if (back)  
                  for (int i = 0; i < info.length; i++) {   
                      accs[i] = 1.0; // if it is cos of back or middle
                  }
                                 
           }
           for (int t = 0; t < info.length; t++){
               lanes[t] = temp;
           }
         }
         return new Move(accs, lanes);
    }
}

