//***********************************************************
//*
//* File:           Group2Player4BB.java
//* Author:         Bhagyashree Bohra, Eric Goldstein, James Rishe
//* Update:         12.08.2004, 12:09pm
//* 
//* Description:    our player
//*
//***********************************************************

package Olympics.g2;

import Olympics.*;
import java.io.Serializable;
import java.util.*;
import java.lang.*;
import java.awt.Color;

public class Group2Player4BB implements IFCPlayer {

    Olympics            _olympics;
    static Random       _random;
    static final String _CNAME = "Group2";
    int R;
    int L;
    int leader;
    boolean breakoutlast = false;
    boolean breakoutone = false;
    int lastRider = 0;
	int lastButOneRider = 0;
	int lastButTwoRider = 0;
        int lastButThreeRider = 0;
    public void register(Olympics __olympics) throws Exception {
        _olympics = __olympics;
	R = _olympics.R();
	_random = new Random();
	leader = -1;
    }

    public String name() throws Exception {
        return _CNAME;
    }

    public Color color() throws Exception {
        return new Color(0.0f,1.0f,0.0f);
    }

    public boolean interactive() throws Exception {
        return false;
    }

    public Move move() throws Exception {

	double[] accs = new double[R];
	int[] lanes = new int[R];
	int teams = _olympics.numTeams();
	int riders = _olympics.R();
	int distance = _olympics.D();
	int numLanes = _olympics.L();
	int initialEnergy = _olympics.E();
	int teamidx = _olympics.indexOf(this);		// our team's index
	int minpos=numLanes, maxpos=-1, avgpos=0;
	int goright=1, stayput=0, goleft=-1;
	boolean leaderDeclared = false;
	double maxSpeed=0;
	boolean allInOneLane=false;   //to check if all players are aligned.
	double myAcc=0;
	boolean backToBack = false;   //to check if all the players are back to back
	boolean allRightOpen = false;
	boolean allLeftOpen = false;
       
	int ridersAlive = riders;
        RiderInfo[][] info = _olympics.TeamStatus();


	// find lane closest to all players
	if( _olympics.currTime()==1 ) {
		for(int i=0; i<riders; i++) {
			if(info[teamidx][i].lane() < minpos)
				minpos = _olympics.TeamStatus(teamidx)[i].lane();
			if(info[teamidx][i].lane() > maxpos)
				maxpos = _olympics.TeamStatus(teamidx)[i].lane();
		}
		//	System.out.println("minpos = "+minpos+"\nmaxpos = "+maxpos);
	}
	avgpos = (maxpos+minpos)/2;
	

	//check if everyone is in the same lane
	int lane = info[teamidx][0].lane();
	if(!breakoutone&&!breakoutlast)
            allInOneLane = true;
	for(int k =1;k<riders;k++)
	    {
		if(info[teamidx][k].lane()!= lane)
		    allInOneLane = false;
	    } 

        
	for(int i=0;i < riders;i++)
	{
	    //if(!breakoutone||!breakoutlast)
		//{
	    //if((!allInOneLane)/*&&(!backToBack)*/) accs[i] = 2 * _random.nextDouble() - 1.0;
	    //	else accs[i] = 1;
	    if(!allInOneLane || riders<2){
		if(info[teamidx][i].lane() < avgpos) 
		    { lanes[i] = goright; accs[i]=0.1;}
		else if(info[teamidx][i].lane() > avgpos) 
		    { lanes[i] = goleft; accs[i]=0.1;}
		else if(info[teamidx][i].lane() == avgpos && !leaderDeclared) {
				leader = i;
				leaderDeclared = true;
				accs[i]=0.2;
			}
		else if(info[teamidx][i].lane() == avgpos) { lanes[i] = stayput;accs[i]=0.15; }
	    }
		//}
        }
	/*	if( leader != -1 ) {
		if(_olympics.currTime() < 30) accs[leader] = 1;
		else if(_olympics.currTime() >= 30 && _olympics.currTime() < 60 ) accs[leader] = -0.5;
		else accs[leader] = 0;
	}
	*/
	
        
        
	//after we are in one lane
	if(leader != -1)
	{
	    //calculate the number of riders alive
	    for(int i = 0; i<riders; i++)
	    {
	    	if(info[teamidx][i].energy()<0.1)
	    		--ridersAlive;		
	    }
	    
	    // int lastRider = 0;
// 	    int lastButOneRider = 0;
// 	    int lastButTwoRider = 0;
    if(allInOneLane)
    {
	 double minPosition = distance;
                    
	    for(int i=0;i<riders;i++)
		{
		    if((info[teamidx][i].position()<minPosition)&&(info[teamidx][i].energy()>0.1))
		    {
			minPosition = info[teamidx][i].position();
			lastRider = i;
		    }
		    
		}
	    

	    if(ridersAlive>1)
		{
		    minPosition = distance;
		    for(int i=0;i<riders;i++)
			{
			    if(i!= lastRider)
				{
				    if((info[teamidx][i].position()<minPosition)&&(info[teamidx][i].energy()>0.1))
					{
					    minPosition = info[teamidx][i].position();
					    lastButOneRider = i;
					}
				}
		    
			}
		}

	    if(ridersAlive>2)
		{
		    minPosition = distance;
		    for(int i=0;i<riders;i++)
			{
			    if(i!= lastRider && i!=lastButOneRider)
				{
				    if((info[teamidx][i].position()<minPosition)&&(info[teamidx][i].energy()>0.1))
					{
					    minPosition = info[teamidx][i].position();
					    lastButTwoRider = i;
					}
				}
		    
			}
		}
            
            if(ridersAlive>3)
		{
		    minPosition = distance;
		    for(int i=0;i<riders;i++)
			{
			    if(i!= lastRider && i!=lastButOneRider && i!= lastButTwoRider)
				{
				    if((info[teamidx][i].position()<minPosition)&&(info[teamidx][i].energy()>0.1))
					{
					    minPosition = info[teamidx][i].position();
					    lastButThreeRider = i;
					}
				}
		    
			}
		}
    }   
       // }

    
	     if((allInOneLane)&&(ridersAlive>3)&&(info[teamidx][lastButThreeRider].energy()>0.1))
           {  maxSpeed = Math.pow(((info[teamidx][lastButThreeRider].energy())/(distance-info[teamidx][lastButThreeRider].position())),0.667);
            //   System.out.println("using max speed of last but three rider");
           }
	   else
               if((allInOneLane)&&(ridersAlive>2)&&(info[teamidx][lastButTwoRider].energy()>0.1))
           {
               maxSpeed = Math.pow(((info[teamidx][lastButTwoRider].energy())/(distance-info[teamidx][lastButTwoRider].position())),0.667);
           //   System.out.println("using max speed of last but two rider") ;
           }
               else if(allInOneLane&&ridersAlive>1&&(info[teamidx][lastButOneRider].energy()>0.1))
               {
                maxSpeed = Math.pow(((info[teamidx][lastButOneRider].energy())/(distance-info[teamidx][lastButOneRider].position())),0.667);
              //  System.out.println("using max speed of but one last rider");
               }
            else if(allInOneLane&&(info[teamidx][lastRider].energy()>0.1))
               {
                maxSpeed = Math.pow(((info[teamidx][lastRider].energy())/(distance-info[teamidx][lastRider].position())),0.667);
              //  System.out.println("using max speed of last rider");
               }
	    //maxSpeed = Math.pow(((info[teamidx][leader].energy())/(distance-info[teamidx][leader].position())),0.667)*2.0;
	    //maxSpeed = Math.pow(((info[teamidx][leader].energy())/(distance-info[teamidx][leader].position())),0.4);
	    maxSpeed = Math.min(maxSpeed*1.2,25);
	
	    //finding the accelerations required to acheive max speed,after all in one lane

//	    System.out.println("early leader" + leader);
	   

	    if(info[teamidx][leader].speed() - maxSpeed > 0.1 && allInOneLane)
		{
		    myAcc = -0.5;
		}
	    else if(info[teamidx][leader].speed() - maxSpeed < -0.1 && allInOneLane)
		{
		    myAcc = 0.5;
		}
	    else
		{
		    myAcc = 0;
		}
	  
	    //if all players are 2m apart from their their team once they are in line
	    
	    if(allInOneLane)
		{
		    for(int k = 1;k<riders;k++)
			{
			    if((info[teamidx][k].position()-info[teamidx][k-1].position())-2 <= 0.1)
				backToBack = true;
			    else
				backToBack = false;

			}
		}
	
           if(allInOneLane||(breakoutlast||breakoutone)) 
           {
            double maxPos = 0,pos;
	    for(int k =0; k< riders;k++)
            {
                pos = info[teamidx][k].position();
                if(_olympics.currTime()%20 == 0 && pos > maxPos){
                    leader = k;
                    maxPos = pos;
                }

                if(_olympics.currTime()%500 == 0){
		//	System.out.println("Rider #"+k+" distance="+pos+ " acc="+accs[k]);
                }
             }
           } 
	    //assigning the same accelrations for all the riders,
	    //once all are in the same lane
	    if((allInOneLane)/*&&(backToBack)*/)
		{
		    accs[leader] = myAcc;
		 //   if(_olympics.currTime() > 100)
			for(int k =0;k<riders;k++)
			    {
				if(k != leader)
				    accs[k]=1;
			    }
		   
		} 
        }    
	
	
	//		System.out.println("=================max speed "+maxSpeed);

	
	//see if there are open positions for all riders in our team on the left or right

	    if(allInOneLane)
	    {
		for(int i=0;i<teams;i++)
		    {
			for(int j=0;j<riders;j++)
			    {
				if(i != teamidx)
				{
				if(info[i][j].lane()!= info[teamidx][0].position()+1)
				    allRightOpen = true;
				else 
				    {
				
					for(int k =0;k<riders;k++)
					{
					    //	System.out.println("position"+ info[i][j].position()+"   my position"+info[teamidx][k]);
						if((info[i][j].position()-info[teamidx][k].position()>2)||(info[i][j].position()-info[teamidx][k].position()<-2))
						allRightOpen = true;
					    else
						allRightOpen = false;
					}
				    
				    }
				if((info[i][j].lane()!= info[teamidx][0].position()-1)&& (i!= teamidx))
				    allLeftOpen = true;
				else
				    {
					for(int k =0;k<riders;k++)
					{
					    if((info[i][j].position()-info[teamidx][k].position()>2)||(info[i][j].position()-info[teamidx][k].position()<-2))
						allLeftOpen = true;
					    else
						allLeftOpen = false;
					}
				    
				    }
			        }
			    }
			    
		    }
	    

		if(!breakoutone&&!breakoutlast)
		    {
		if((allLeftOpen)&&(allRightOpen))
		{    
		    if(_random.nextDouble()>0.5)
		    {
			for(int i=0;i<riders;i++)
			{
			    lanes[i]=goleft;
			}
		    }
		    else 
		    {
			for(int i=0;i<riders;i++)
			{
			    lanes[i]=goright;
			}
			
		    }
		}
		else if(allLeftOpen)
		{   
		    
		    for(int i=0;i<riders;i++)
			{
			    lanes[i]=goleft;
			}
			
		}
		else if(allRightOpen)
		    
		{   
		    
		    for(int i=0;i<riders;i++)
			{
			    lanes[i]=goright;
			}
			
		}


			
	    }
	    }

	
	    
	if(_olympics.currTime()%500 == 0 && allInOneLane){
	    /*	    System.out.println("The leader is " + leader);
	    System.out.println("MaxSpeed = " + maxSpeed);
	    System.out.println("Leader's Speed = " + info[teamidx][leader].speed());
	    System.out.println("Leader's energy = " + info[teamidx][leader].energy());*/
	}
        
	// break out of line at the emd
	//	if already broken out, do nothing    
	if(breakoutlast||breakoutone)
	  { 
		for(int i =0;i<riders;i++)
		    {
			if(i==lastRider&&breakoutlast)
			    {
			    if(_random.nextDouble()<0.3)
				lanes[i]=goleft;
			    else 
                            {if(_random.nextDouble()<0.55)
				lanes[i]=goright;
                            else
				lanes[i]=stayput;
                            }
			    }
                            if(i==lastButOneRider&&breakoutone)
			    {
			    if(_random.nextDouble()<0.3)
				lanes[i]=goleft;
			    else 
                            {if(_random.nextDouble()<0.55)
				lanes[i]=goright;
                            else
				lanes[i]=stayput;
                            }
			    }
			lanes[i]=stayput;
		    }
	   }
	
	 if((info[teamidx][lastRider].energy()*1.0>Math.pow(25,1.5)*distance-info[teamidx][lastRider].position())||(info[teamidx][lastRider].position()/distance>0.97))
		    {
			if(!breakoutone||!breakoutlast)
			{
			if(info[teamidx][lastRider].lane()== info[teamidx][leader].lane()&&!breakoutlast)
			    {
				lanes[lastRider]=goleft;
				breakoutlast = true;
                        }
				  if((info[teamidx][lastButOneRider].energy()*1.0>Math.pow(25,1.5)*(distance-info[teamidx][lastButOneRider].position()))||(info[teamidx][lastButOneRider].position()/distance>0.97))
				   {   if(info[teamidx][lastButOneRider].lane()==info[teamidx][leader].lane()&&!breakoutone)
                                       {   lanes[lastButOneRider]=goright;
                                     breakoutone = true;}
				    
                                  }
                        
                                
                       }
	/*		else if(allRightOpen&&!allLeftOpen)
			    {
				lanes[lastRider]=goright;
				breakoutlast = true;
				
			    }
			else if(allLeftOpen&&!allRightOpen)
			    {
				lanes[lastRider]=goleft;
				breakoutlast = true;
			    }
         */   
			for(int i = 0;i<riders;i++)
			    {
				double mspeed = 0.0;
				if(info[teamidx][i].energy()>0)
				    {
					mspeed= Math.pow(((info[teamidx][i].energy())/(distance-info[teamidx][i].position())),0.667);
					mspeed = Math.min(mspeed*1.0,25);
					if(info[teamidx][i].speed() - mspeed > 0.1)
					    {
						accs[i] = -0.5;
					    }
					else if(info[teamidx][i].speed() - mspeed < -0.1)
					    {
						accs[i] = 0.5;
					    }
					else
					    {
						accs[i] = 0;
					    }
				    }
			    }
            
         }
		
	
/*	    if(allRightOpen)
                {System.out.println("All right open");}
            else
                {System.out.println("all right not open");}
            if(allLeftOpen)
                {System.out.println("All left Open");}
            else
                {System.out.println("all left not open");}
	    if(breakoutlast)
		{System.out.println("breakoutlast");}
	    if(breakoutone)
		{System.out.println("breakoutone");}
			
               System.out.println("current time"+_olympics.currTime());
                System.out.println("last rider"+ lastRider+"last rider position"+info[teamidx][lastRider].position()+"last rider energy"+info[teamidx][lastRider].energy()+"last rider lane"+info[teamidx][lastRider].lane());
		System.out.println("last but one rider"+lastButOneRider+"last but one rider position"+info[teamidx][lastButOneRider].position()+"last but one rider energy"+info[teamidx][lastButOneRider].energy()+"last but one rider lane"+info[teamidx][lastButOneRider].lane());
		System.out.println("last but two rider"+lastButTwoRider+"last but two rider position"+info[teamidx][lastButTwoRider].position()+"last but two rider energy"+info[teamidx][lastButTwoRider].energy()+"last but two rider lane"+info[teamidx][lastButTwoRider].lane());
                System.out.println("last but three rider"+lastButThreeRider+"last but three rider position"+info[teamidx][lastButThreeRider].position()+"last but three rider energy"+info[teamidx][lastButThreeRider].energy()+"last but three rider lane"+info[teamidx][lastButThreeRider].lane());
		if(leader != -1)
                { System.out.println("leader"+leader+"letter"+info[teamidx][leader].position());}
		System.out.println("riders alive"+ridersAlive);
	*/   
		 
        return new Move(accs, lanes);
    }
}
