#include "prolo.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>



/* Quelques constantes... */

#define pi M_PI
#define sqr(x) ((x)*(x))
#define MAX 300
#define RAYON_MIN 1
#define OUVERTURE_DEPART pi/4
#define DEFENSE_DISTANCE 5
#define DEFENSE_OUVERTURE 5
#define ATTAQUE_DISTANCE 1
#define ATTAQUE_OUVERTURE 0.01
#define GRATUIT_FREQ 10/10
#define GRATUIT_OUVERTURE 0.5
#define AIDE_TIMELIMIT 10000
#define AIDE_NBLIMIT 1
#define AIDE_OUVERTURE (2*r4d2_get_speed()+1)



/* Variables globales */

struct
{
  int team;
  float x,y;
  float angle,ouverture;
} akx[MAX];

struct
{
  float x,y,r;
} vise;

int capturing[MAX];

int nation;



/* Player_Init */

void player_init(int team_id, int nb_team)
{
  int i;

  nation=team_id;
  printf("version 2\n");
  printf("je suis %d\n",nation);
  printf("akx_see_power : %f\n",akx_get_see_power());

  for (i=0;i<MAX;i++)
  {
    akx[i].ouverture=OUVERTURE_DEPART;
    akx[i].team=-1;
    capturing[i]=-1;
  }

  return;
}



/* Player_New_Turn */

void player_new_turn(int turn_number)
{
  int i,j,best_akx,best_r4d2;
  float best,dist;

  /* Mise a jour de la table locale des AnaKronoX */
  for (i=0;i<MAX;i++) if (akx_get_team(i)!=-1)
  {
    if (akx[i].team==-1)
    {
      printf("akx %d trouve\n",i);
      akx[i].x=akx_get_pos_x(i);
      akx[i].y=akx_get_pos_y(i);
      akx[i].team=akx_get_team(i);
    }
    if (akx[i].team!=akx_get_team(i))
    {
      printf("akx %d a change de team\n",i);
      akx[i].team=akx_get_team(i);
    }
    if ((akx[i].x!=akx_get_pos_x(i)) || (akx[i].y!=akx_get_pos_y(i)))
    {
      printf("akx %d a bouge\n",i);
      akx[i].x=akx_get_pos_x(i);
      akx[i].y=akx_get_pos_y(i);
    }
  }

  /* S'il ne reste que peu de r4d2 ou qu'on approche de la fin de partie, on defend le plus possible un des r4d2 restants */
  if ((turn_counter()>=AIDE_TIMELIMIT) || (map_count_my_r4d2()<=AIDE_NBLIMIT))
    for (i=0;i<MAX;i++) if (r4d2_get_team(i)==nation)
    {
      printf("AIDE r4d2 %d\n",i);
      vise.x=r4d2_get_pos_x(i);
      vise.y=r4d2_get_pos_y(i);
      vise.r=AIDE_OUVERTURE;
      return;
    }

  /* Recherche du r4d2 ennemi le plus proche d'un de mes AnaKronoX */
  best=10000;
  for (i=0;i<MAX;i++) if (((akx_get_team(i)==nation)||(akx_get_team(i))==0) && ((j=map_get_nearest_r4d2_plot(akx_get_pos_x(i),akx_get_pos_y(i),-nation))!=-1))
  {
    dist=sqrt(sqr(akx_get_pos_x(i)-r4d2_get_pos_x(j))
             +sqr(akx_get_pos_y(i)-r4d2_get_pos_y(j)));
    if (dist<best)
    {
      best=dist;
      best_akx=i;
      best_r4d2=j;
    }
  }

  /* S'il y a un r4d2 ennemi tres proche d'un de mes AnaKronoX (surement en train de convertir donc surement imobile, on le vise tres serre */
  if (best<ATTAQUE_DISTANCE)
  {
    printf("ATTAQUE %d\n",best_r4d2);
    vise.x=r4d2_get_pos_x(best_r4d2);
    vise.y=r4d2_get_pos_y(best_r4d2);
    vise.r=ATTAQUE_OUVERTURE;
    return;
  }

  /* S'il y a un r4d2 ennemi assez proche d'un des mes AnaKronoX, on le gene faisant un defense de zone autour de l'AnaKronoX */
  if (best<DEFENSE_DISTANCE)
  {
    printf("DEFENSE %d\n",best_akx);
    vise.x=akx_get_pos_x(best_akx);
    vise.y=akx_get_pos_y(best_akx);
    vise.r=DEFENSE_OUVERTURE;
    return;
  }
  
  /* On tente une attaque "gratuite" sur un r4d2 ennemi de temps en temps */
  if (map_random()<GRATUIT_FREQ)
    for (i=0;i<MAX;i++) if ((r4d2_get_team(i)!=-1) && (r4d2_get_team(i)!=nation))
    {
      vise.x=r4d2_get_pos_x(i);
      vise.y=r4d2_get_pos_y(i);
      vise.r=GRATUIT_OUVERTURE;
      return;
    }

  /* Sinon on ne vise rien de special (on fera du scanning) */
  vise.r=-1;
  return;
}



/* Player_AKX_Turn */

void player_akx_turn(int akx_id)
{
  float rayon,ouverture,tcos,tsin;

  /* Si on n'a plus de r4d2, on fait une defense de zone tres concentree, en bougeant une fois sur 3 */
  if (map_count_my_r4d2()==0)
  {
    /* J'utilise l'angle comme boolean pour alterner deplacement/defense */
    if (akx[akx_id].angle<2)
    {
      akx[akx_id].angle++;
      vise.x=akx_get_pos_x(akx_id);
      vise.y=akx_get_pos_y(akx_id);
      vise.r=RAYON_MIN;
    }
    else
    {
      akx[akx_id].angle=0;
      akx_move(akx_id,1,1);
      return;
    }
  }

  /* Si on a une directive de visee, on l'execute */
  if (vise.r!=-1)
  {
    rayon=sqrt(sqr(akx_get_pos_x(akx_id)-vise.x)
              +sqr(akx_get_pos_y(akx_id)-vise.y));
    /* Si la distance entre l'AnaKronoX et sa cible est trop faible, on fait une defense circulaire */
    if (rayon<RAYON_MIN)
      akx_pulse(akx_id,akx_get_pos_x(akx_id)+RAYON_MIN,akx_get_pos_y(akx_id),2*pi);
    /* Sinon on vise la cible avec l'ouverture demandee, en centrant au maximum */
    else
    {
      tcos=(vise.x-akx_get_pos_x(akx_id))/rayon;
      tsin=(vise.y-akx_get_pos_y(akx_id))/rayon;
      ouverture=2*atan(vise.r/rayon);
      akx_pulse(akx_id,vise.x+tcos*vise.r,vise.y+tsin*vise.r,ouverture);
    }
    return;
  }

  /* Sinon on scanne la carte pour trouver de nouveaux objectifs */
  rayon=sqrt(2*akx_get_power()/(akx_get_see_power()*akx[akx_id].ouverture));
  rayon--;
  akx_pulse(akx_id,akx_get_pos_x(akx_id)+cos(akx[akx_id].angle)*rayon,akx_get_pos_y(akx_id)+sin(akx[akx_id].angle)*rayon,akx[akx_id].ouverture);

  /* Calcul du prochain scan : on evite de scanner en dehors de la carte */
  do
  {
    akx[akx_id].angle+=akx[akx_id].ouverture;
    while (akx[akx_id].angle>=2*pi) akx[akx_id].angle-=2*pi;
    /* Si on a fait un tour complet, on scanne plus serre et plus loin */
    if ((akx[akx_id].angle>=0) && (akx[akx_id].angle<akx[akx_id].ouverture))
    {
      akx[akx_id].angle=0;
      /* Si on scanne deja un rayon plus grand que la map, on repart sur un petit scan */
      if ((rayon>=map_get_size_x()) && (rayon>=map_get_size_y())) akx[akx_id].ouverture=OUVERTURE_DEPART;
      else akx[akx_id].ouverture=akx[akx_id].ouverture/2;
    }
    rayon=sqrt(2*akx_get_power()/(akx_get_see_power()*akx[akx_id].ouverture));
  }
  while ((akx_get_pos_x(akx_id)+cos(akx[akx_id].angle)*rayon<-1) ||
         (akx_get_pos_x(akx_id)+cos(akx[akx_id].angle)*rayon>map_get_size_x()+1) ||
	 (akx_get_pos_y(akx_id)+sin(akx[akx_id].angle)*rayon<-1) ||
         (akx_get_pos_y(akx_id)+sin(akx[akx_id].angle)*rayon>map_get_size_y()+1));
   
  return;
}



int being_captured(int akx_id)
/* Retourne 1 si l'AnaKronoX passe en parametre est deja en cours de capture */
{
  int i;
  for (i=0;i<MAX;i++) if (capturing[i]==akx_id) return(1);
  return(0);
}

int choose_nearest_akx_plot(int x, int y)
/* Retourne l'AnaKronoX le plus proche du point (x,y) et qui n'est pas deja en cours de capture */
{
  float dist,best=10000;
  int id=-1,i;

  for (i=0;i<MAX;i++) if ((akx[i].team!=-1) && (akx[i].team!=nation) && (!being_captured(i)))
  {
    dist=sqrt(sqr(akx_get_pos_x(i)-x)+sqr(akx_get_pos_y(i)-y));
    if (dist<best) 
    { 
      best=dist; 
      id=i; 
    }
  }
  return(id);
}


/* Player_R4D2_Turn */

void player_r4d2_turn(int r4d2_id)
{
  int i;

  if (akx_get_team(capturing[r4d2_id])==nation) 
  {
    printf("%d -/-> %d\n",r4d2_id,capturing[r4d2_id]);
    capturing[r4d2_id]=-1;
  }

  if (capturing[r4d2_id]==-1)
  {
    if ((i=choose_nearest_akx_plot(r4d2_get_pos_x(r4d2_id),r4d2_get_pos_y(r4d2_id)))==-1)
      r4d2_move(r4d2_id,map_get_size_x()/2,map_get_size_y()/2);
    else
    {
      r4d2_move(r4d2_id,akx[i].x,akx[i].y);
      capturing[r4d2_id]=i;
      printf("%d ---> %d\n",r4d2_id,i);
    }
  }
  else
    if (sqrt(sqr(r4d2_get_pos_x(r4d2_id)-akx[capturing[r4d2_id]].x)+
            sqr(r4d2_get_pos_y(r4d2_id)-akx[capturing[r4d2_id]].y))<1)
      r4d2_take_akx(r4d2_id,capturing[r4d2_id]);
    else
      r4d2_move(r4d2_id,akx[capturing[r4d2_id]].x,akx[capturing[r4d2_id]].y);
  return;
}