version 0.4
[zeRace] / bot.c
diff --git a/bot.c b/bot.c
new file mode 100644 (file)
index 0000000..ef93b04
--- /dev/null
+++ b/bot.c
@@ -0,0 +1,266 @@
+#include "bot.h"
+
+#define DELAY 7
+#define MAXRECORDKEYS 9999
+
+/* tracklist */
+struct _tracklist *tracklist;
+
+/* user setup */
+struct _config
+{
+  char pseudo[MAXLINELENGTH];
+  char url[MAXLINELENGTH];
+  int fullscreen;
+  int sound;
+  int tire;
+  SDLKey up;
+  SDLKey down;
+  SDLKey left;
+  SDLKey right;
+  int color;
+} config = {"anonymous","",0,0,1,SDLK_UP,SDLK_DOWN,SDLK_LEFT,SDLK_RIGHT,6};
+
+/* full script for a lap */
+struct _record
+{
+  float x,y,angle,speed;
+  char keys[MAXRECORDKEYS];
+  int time;
+};
+
+/* network stuff */
+UDPsocket udpsock=NULL;
+UDPpacket *packet;
+int network_speed=1;
+int aleas;
+
+
+/* exit the game and clean */
+void zeRace_exit()
+{
+  printf("quit\n");
+  SDLNet_Quit();
+  SDL_Quit();
+  exit(0);
+}
+
+
+/* initialize the game */
+void zeRace_init()
+{
+  /* do a clean exit in case of emergency */
+  signal(SIGINT,zeRace_exit);
+  signal(SIGTERM,zeRace_exit);
+
+  /* get the list of local tracks */
+  if (!zeRace_get_tracks(&tracklist)) zeRace_exit();
+  
+  srand(time(NULL));
+  
+  /* robot configuration */
+  sprintf(config.pseudo,"\"%s\" bot(%d)",bot_name(),aleas);
+  config.color=rand()%12;
+  
+  if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)<0)
+  {
+    fprintf(stderr,"could not initialize SDL : %s\n",SDL_GetError());
+    zeRace_exit();
+  }
+  atexit(SDL_Quit);
+  
+  if (SDLNet_Init()==-1)
+  {
+    fprintf(stderr,"could not initialize SDLNet : %s\n",SDLNet_GetError());
+    zeRace_exit();
+  }
+
+  packet=SDLNet_AllocPacket(1024);
+  if (!packet)
+  {
+    fprintf(stderr,"SDLNet_AllocPacket: %s\n",SDLNet_GetError());
+    zeRace_exit();
+  }
+}
+
+
+/* launch a new race */
+void zeRace_launch(int alltime,int go)
+{
+  SDL_Surface *cir,*fun;
+  int ku=0,kd=0,kl=0,kr=0,i;
+  struct _car car;
+  int delay=DELAY;
+  int lastack=alltime;
+  struct _record net;
+
+  cir=IMG_Load(tracklist->full);
+  fun=IMG_Load(tracklist->function);
+  
+  car.speed=0;
+  car.angle=tracklist->a*2*M_PI/360;
+  car.ox=car.x=tracklist->x;
+  car.oy=car.y=tracklist->y;
+  car.lastcheck=0;
+  car.w=30;
+  car.h=30;
+  net.time=0;
+
+  /* startup countdown */
+  for (i=4;i>=-1;i--)
+  {
+    if (!go) break;
+    if (i!=-1) SDL_Delay(1000);
+  }
+  
+  /* main loop */
+  for (;;)
+  {
+    /* call the IA */
+    bot_ia(tracklist->name,&car,fun,&ku,&kd,&kl,&kr);
+    
+    /* random movement if asked */
+    if (aleas) if (rand()%aleas==0)
+    {
+      ku=rand()%2;
+      kl=rand()%2;
+      kr=rand()%2;
+      kd=rand()%2;
+    }
+    
+    if (udpsock)
+    {
+      net.keys[net.time]=(ku<<3 | kd<<2 | kl<<1 | kr)+'A';
+      net.keys[net.time+1]='\0';
+    }
+
+    delay=DELAY;
+    /* if we are in network mode */
+    if (udpsock!=NULL)
+    {
+      char *tmp;
+      while (SDLNet_UDP_Recv(udpsock,packet)) if (strcmp(packet->data,"positions")==0)
+      {
+        int servertime,clienttime,nb;
+        servertime=SDLNet_Read32(packet->data+strlen("positions")+1);
+        clienttime=SDLNet_Read32(packet->data+strlen("positions")+1+4);
+        nb=SDLNet_Read16(packet->data+strlen("positions")+1+4+4);
+        if (clienttime>lastack)
+        {
+          memcpy(net.keys,net.keys+clienttime-lastack,net.time+1);
+          net.time-=clienttime-lastack;
+          if (clienttime>servertime+5) delay+=DELAY;
+          if (clienttime<servertime-5) delay-=DELAY;
+          if (delay<0) delay=0;
+          lastack=clienttime;
+        }
+      }
+      else /* end of this network race */
+      {
+        SDL_FreeSurface(cir);
+        SDL_FreeSurface(fun);
+        return;
+      }
+      if (strlen(net.keys)!=0)
+      {
+        tmp=packet->data;
+        strcpy(tmp,"keys");
+        tmp+=strlen(tmp)+1;
+        SDLNet_Write32(lastack,tmp);
+        tmp+=4;
+        strcpy(tmp,net.keys);
+        tmp+=strlen(tmp)+1;
+        packet->len=(void *)tmp-(void *)packet->data+10;
+        if (net.time%network_speed==0) if (!SDLNet_UDP_Send(udpsock,-1,packet))
+        {
+          fprintf(stderr,"SDLNet_UDP_Send: %s\n",SDLNet_GetError());
+          exit(2);
+        };
+      }
+    }
+
+    /* move the car */
+    move_car(&car,(ku<<3 | kd<<2 | kl<<1 | kr),fun);
+
+    /* let the system breath */
+    SDL_Delay(delay);
+    
+    /* game time */
+    net.time++;
+    if (udpsock && net.time>MAX_LAG)
+    {
+      fprintf(stderr,"timeout !\n");
+      SDL_FreeSurface(cir);
+      SDL_FreeSurface(fun);
+      return;
+    }
+    alltime++;
+  }
+}
+
+
+/* connect to a server */
+void zeRace_connect(char *host,int port)
+{
+  char *tmp;
+  int lag=0;
+  udpsock=SDLNet_UDP_Open(0);
+  if (udpsock==NULL)
+  {
+    fprintf(stderr,"SDLNet_UDP_Open: %s\n",SDLNet_GetError());
+    zeRace_exit();
+  }
+  SDLNet_ResolveHost(&packet->address,host,port);
+  tmp=packet->data;
+  strcpy(tmp,"connect");
+  tmp+=strlen(tmp)+1;
+  strcpy(tmp,config.pseudo);
+  tmp+=strlen(tmp)+1;
+  SDLNet_Write16(config.color,tmp);
+  tmp+=2;
+  packet->len=(void *)tmp-(void *)packet->data;
+  SDLNet_UDP_Send(udpsock,-1,packet);
+  /* network loop */
+  while (SDLNet_UDP_Recv(udpsock,packet) || lag<MAX_LAG)
+  {
+    tmp=packet->data;
+    if (strcmp(tmp,"track")==0)
+    {
+      struct _tracklist *loopcheck=tracklist;
+      int time;
+      char go;
+      tmp+=strlen(tmp)+1;
+      go=*tmp++;
+      printf("server asked for track : %s\n",tmp);
+      while (tracklist->next!=loopcheck) if (strcmp(tracklist->name,tmp)==0) break; else tracklist=tracklist->next;
+      if (strcmp(tracklist->name,tmp)!=0)
+      {
+        fprintf(stderr,"unknown track : %s\n",tmp);
+        zeRace_exit();
+      }
+      tmp+=strlen(tmp)+1;
+      time=SDLNet_Read32(tmp);
+      tmp+=4;
+      network_speed=SDLNet_Read32(tmp);
+      zeRace_launch(time,go);
+      if (strcmp(packet->data,"finish")==0) SDL_Delay(5000);
+      lag=0;
+    }
+    SDL_Delay(7);
+    lag++;
+  }
+  SDLNet_UDP_Close(udpsock);
+  udpsock=NULL;
+}
+
+
+/* main program */
+int main(int argc,char *argv[])
+{
+  if (argc!=4) { fprintf(stderr,"Usage : %s host port random\n  host   : host or ip of the server to connect to\n  port   : port number of the server to connect to\n  random : frequency of random moves (0 = no random moves, 1 = only random, 1000 = 1/1000 random moves)\n",argv[0]); exit(1); }
+  aleas=atoi(argv[3]);
+  zeRace_init();
+  zeRace_connect(argv[1],atoi(argv[2]));
+  zeRace_exit();
+  return 0;
+}