// Tobias Lindstrøm Jensen implementation of the soccer game
// ver 0.1
// tlj@es.aau.dk
//

public class FCFeisto extends Team {
	int team, w, h;
	double[] dir;
	double[] speed;
	double[] shotdir;
	double[] shotspeed;
	double attx,atty;
			int homex, homey,goalx,goaly,oteam;

	// Intializes with what team this is, and the height and width of the field
	FCFeisto(int team, int w, int h) {
		this.team = team; // It's good to know, what team you are!
		this.w = w;
		this.h = h;
				
				
		if(team==0)
				oteam=1;
		else
				oteam = 0;

		dir = new double[5];
		speed = new double[5];
		shotdir = new double[5];
		shotspeed = new double[5];
		
		// Position of own goal...
		homex = 0;
		homey = h/2;
		if(team==1) homex = w;
		
		
		goalx = 0;
		goaly = h/2;
		if(team==0) goalx = w;

		// Home of the striker
		attx = 3*w/4;
		atty = h/2+Math.random()*50;
	}

	// Distance function...
	double dist(double x, double y, double a, double b) {
		return Math.sqrt((x-a)*(x-a)+(y-b)*(y-b));
	}

	// Pick a random direction...
	double randomDir() {
		return Math.random()*2*Math.PI;
	}

	// Direction to oppnents goal
	double goalDir(double x, double y) {
		
		return getDir(x,y,goalx,goaly);
	}

	// Direction to own goal
	double homeGoalDir(double x, double y) {
		return getDir(x,y,homex,homey);
	}

	// Get the direction one has to go to get from (x,y) to (a,b)
	double getDir(double x, double y, double a, double b) {
		return Math.atan2(b-y,a-x);			
	}

	int oppTeam(int ownteam){
		if(ownteam == 0){
			return 1;}
		else
			return 0;
	}
	//Identify which team are in ball position, or soon will be. The closest team
	int findBallTeam(double[][][] playerPos,double[] ballPos){
		double minD=100000;
		double d ;
		int ballTeam = team;

		for(int i=0; i<5; i++) {
			d = dist(playerPos[team][i][0],playerPos[team][i][1],ballPos[0],ballPos[1]);
			if(d < minD) {
				minD = d;
			}
		}
		
		for(int i=0; i<5; i++) {
			d = dist(playerPos[oteam][i][0],playerPos[oteam][i][1],ballPos[0],ballPos[1]);
			if(d + w/40 < minD) {
				minD = d;
				ballTeam = oteam;
			}
		}
		return ballTeam;	
	}

	//Find the closest player on you own team
	int findClosestPlayer(int team,double[][][] playerPos,double[] ballPos){
		double minD=100000;
		double d ;
		int closest=0;
 
		for(int i=1; i<5; i++) {
			d = dist(playerPos[team][i][0],playerPos[team][i][1],ballPos[0],ballPos[1]);
			if(d < minD) {
				minD = d;
				closest = i;
			}
		}
		return closest;
	}

		int[] otherPlayers(int gk,int cp){
					int[] op = new int[3];
					int p=0;
					int i;

					for(i=0;i<5;i++){
							if(i!=gk && i!=cp){
									op[p] = i;
									p++;
							}		
					}
					return op;

			}

		int[] mostAttackingPlayers(double[][][] playerPos,int number){
				double[] dtg = new double[5];//dist to own goal
				int[] index = new int[5];
				int[] rindex = new int[number];
				int i;
				int oteam = oppTeam(team);

				for(i=0;i<5;i++){
						dtg[i] = Math.abs(playerPos[oteam][i][0]-homex);	
				}
				
				//sort it all
				index = sortMin(dtg,5);
				
				//select the number with smallest distance
			  for(i=0;i<number;i++){
						rindex[i] = index[i];	
				}			
				
				return rindex;
		}

    int[] mostDefensivePlayers(double[][][] playerPos,int number){
				double[] dtg = new double[5];//dist to own goal
				int[] index = new int[5];
				int[] rindex = new int[number];
				int i;
				int oteam = oppTeam(team);

				for(i=0;i<5;i++){
						dtg[i] = Math.abs(playerPos[oteam][i][0]-goalx);	
				}
				
				//sort it all
				index = sortMin(dtg,5);
				
				//select the number with smallest distance
			  for(i=0;i<number;i++){
						rindex[i] = index[i];	
				}			
				
				return rindex;				
		}

		//Sort by minimum
		int[] sortMin(double[] dtg,int l){
				int notSorted = 0;
				int[] index = new int[5];
				int i,ti;
				double t;
				int flag=0;
				for(i=0;i<l;i++)
						index[i]=i;
			
				while(notSorted == 0){
						flag = 0;
						for(i=0;i<l-1;i++){
								if( dtg[i] < dtg[i+1] ){
										t = dtg[i];
										dtg[i] = dtg[i+1];
										dtg[i+1] = t;
										ti = index[i];
										index[i] = index[i+1];
										index[i+1] = ti;
										flag = 1;
								}
						}
						if(flag == 0)
								notSorted = 1; 
								
				}

				return index;
		}

		double[][] getCoveringPositions(int[] map,double[][][] playerPos,double[] ballPos,double rap){
				double dir;
				int oteam = oppTeam(team);
				double[][] cvp = new double[3][2];
				int i;

				for(i=0;i<3;i++){
						dir = getDir(playerPos[oteam][map[i]][0],playerPos[oteam][map[i]][1],ballPos[0],ballPos[1]);
						cvp[i][0] = playerPos[oteam][map[i]][0]+Math.cos(dir)*rap;
						cvp[i][1] = playerPos[oteam][map[i]][1]+Math.sin(dir)*rap;
				}
				return cvp;
		}

		double[] matchSmallestDist(double[][] cvp,int[] op,double[][][] playerPos){
				double[] dir = new double[3];
				int i,k,l;
				int[] ap = new int[3];
				double[] d;
				int[] index;
				int pl = 3;

				for(l=0;l<3;l++){
						ap[l] = l;
				}

				for(i=0;i<3;i++){
						d = new double[pl];
						index = new int[pl];

						for(k=0;k<pl;k++){
								d[k] = dist(cvp[i][0],cvp[i][1],playerPos[team][op[k]][0],playerPos[team][op[k]][1]);
						}
						index = sortMin(d,pl);
						dir[i] = getDir(playerPos[team][op[i]][0],playerPos[team][op[i]][1],cvp[i][0],cvp[i][1]);
						int[] oap = ap;
						pl = pl - 1;
						ap = new int[pl];
						
						//remove index player k from the search
						int h=0;
						for(l=0;l<pl;l++){
								if(oap[l] != oap[index[0]]){
										ap[h] = oap[l];
										h++;
								}
						}
					
				}

				return dir;
		}

		int playerUpfield(double[][][] playerPos,int p){
				int op=0;
				double[] dv = new double[4];
				int[] di = new int[4];
		
				for(int j=0;j<4;j++){
						dv[j]=0;
						di[j]=0;
				}

				double d = dist(playerPos[team][p][0],playerPos[team][p][1],goalx,goaly);
				
				int h=0;
				for(int i=1;i<5;i++){
						double dc = dist(playerPos[team][i][0],playerPos[team][i][1],goalx,goaly);
						if(dc+w/8.0 < d){
								dv[h] = dc;
								di[h] = i;
								h++;
						}
				}
				
				if(h!=0){
						int[] index = new int[h];
						index = sortMin(dv,h);
						op = di[index[h]]; //last index is the one closest who is further ahead
				}

				return op;
		}

	// What to do, what to do...
	double[][] action(double[][][] playerPos, double[] ballPos, double time, int[] score) {
		double[][] a = new double[5][4];
		int defence=0,cp,gk,i;
		double ballteam = findBallTeam(playerPos,ballPos); //the team with the ball
		
		//reset the values
		for(i=0; i<5; i++) {
			dir[i]=0;
			speed[i]=0;
			shotdir[i]=	goalDir(playerPos[team][i][0],playerPos[team][i][1]);
			shotspeed[i] = 4.0; //standart is dripple
		}

		gk = 0;

		cp = findClosestPlayer(team,playerPos,ballPos);
		dir[cp] = getDir(playerPos[team][cp][0],playerPos[team][cp][1],ballPos[0],ballPos[1]);
		speed[cp] = 3; //full speed

		// the other three players positions them on the inside of the three most defensive players, if in attack, or three most offensive players if in attack
		
		int[] op = new int[3]; 
		op = otherPlayers(gk,cp);
		int[] map = new int[3];

		int bt = findBallTeam(playerPos,ballPos);
	
		if(bt == team)
				map	= mostDefensivePlayers(playerPos,3); // on the other team
		else
				map	= mostAttackingPlayers(playerPos,3);  // on the other team
		
		double rap = w / 10.0;
 
		//get the three covering position
		double[][] cvp = new double[3][2];
		cvp = getCoveringPositions(map,playerPos,ballPos,rap);
		double[] dirop = new double[3];
		dirop = matchSmallestDist(cvp,op,playerPos);

		for(i=0;i<3;i++){
				dir[op[i]] = dirop[i];
				speed[op[i]] = 3.0;
		}

		//if cp is close enough to kick the ball
		if(dist(playerPos[team][cp][0],playerPos[team][cp][1],ballPos[0],ballPos[1]) < 15.0 ){
				
				//if close enough to the goal, shoot
				if(dist(playerPos[team][cp][0],playerPos[team][cp][1],goalx,goaly) < w/5){
						shotdir[cp] = goalDir(playerPos[team][cp][0],playerPos[team][cp][1]) + (Math.random()-0.5)*2*Math.PI/20.0;
						shotspeed[cp] = 15;
				}
				
				//if there is a player upfield, try shoot to him.
				else if(playerUpfield(playerPos,cp) != 0){
						int k=playerUpfield(playerPos,cp);
						shotdir[cp] = getDir(playerPos[team][cp][0],playerPos[team][cp][1],playerPos[team][k][0],playerPos[team][k][1]);
						shotspeed[cp] = 15;
				} //otherwise dripple to goal. From reset

		}

		 //the goal keeper just stays between the goal and the ball
		double r=w/22.0;
		double gba = -homeGoalDir(ballPos[0],ballPos[1]);
		dir[gk] = getDir(playerPos[team][gk][0],playerPos[team][gk][1],homex-Math.cos(gba)*r,homey+Math.sin(gba)*r);

		// this is too avoid that the goaly jitters, because he always moves with speed 3.0
		if(dist(playerPos[team][gk][0],playerPos[team][gk][1],homex-Math.cos(gba)*r,homey+Math.sin(gba)*r) > w/50.0)
				speed[gk] = 3.0;
		else 
				speed[gk] = 0.2;


		if(dist(playerPos[team][gk][0],playerPos[team][gk][1],ballPos[0],ballPos[1]) < 15){
				shotdir[gk] = goalDir(playerPos[team][gk][0],playerPos[team][gk][1]) + (Math.random()-0.5)*2*Math.PI/4;
				shotspeed[gk] = 15;

				//make sure no others are kicking, otherwise it could go into your own goal
				for(i=1; i<5; i++) {
						shotdir[i]=	0.0;
						shotspeed[i] = 0.0; //standart is dripple
				}
		}

		// save the orders for returning
		for(i=0; i<5; i++) {
			a[i][0] = dir[i];
			a[i][1] = speed[i];
			a[i][2] = shotdir[i];
			a[i][3] = shotspeed[i];
		}

		return a;
	}
}

