BattleBots: le tournoi

69

Les résultats sont là, le concours est terminé.
Le vainqueur est EvilBot d’ arshajii avec 14 victoires sur Neo-Bot avec 13 victoires et CentreBot et LastStand avec 11 victoires chacun.

Scores de la dernière manche

Results:
java Rifter:                 9  match wins (45 total bout wins)
java EvadeBot:               10 match wins (44 total bout wins)
java EvilBot:                14 match wins (59 total bout wins)
java LastStand:              11 match wins (43 total bout wins)
java UltraBot:               9  match wins (40 total bout wins)
python ReadyAimShoot.py:     8  match wins (36 total bout wins)
./SpiralBot:                 0  match wins (1 total bout wins)
python DodgingTurret.py:     8  match wins (43 total bout wins)
ruby1.9 TroubleAndStrafe.rb: 8  match wins (41 total bout wins)
./RandomBot:                 1  match wins (6 total bout wins)
python StraightShooter.py:   8  match wins (41 total bout wins)
python mineminemine.py:      3  match wins (14 total bout wins)
./CamperBot:                 5  match wins (20 total bout wins)
python3.3 CunningPlanBot.py: 3  match wins (15 total bout wins)
node CentreBot.js:           11 match wins (44 total bout wins)
node Neo-Bot.js:             13 match wins (59 total bout wins)
python NinjaPy.py:           3  match wins (19 total bout wins)

C'est un défi . Le but est d’écrire un bot qui vaincra plus d’autres bots que d’autres.

Le jeu

Les robots seront tous opposés 2 à la fois dans une arène 10x10 avec la tâche de réduire l'énergie de l'adversaire de 10 à 0 avant que sa propre énergie ne soit réduite à 0.

Chaque match consistera en 5 combats. Le vainqueur du match est le vainqueur du plus grand nombre de combats. Le nombre total de victoires de match et de victoires de combat sera stocké par le programme de contrôle et sera utilisé pour déterminer le vainqueur final du concours. Le gagnant reçoit la grosse coche verte et l'adulation des masses.

Chaque combat se déroulera en plusieurs tours. Au début de chaque tour, l'état actuel de l'arène sera donné à chaque bot qui lui répondra ensuite avec une commande pour déterminer ce qu'il veut faire ensuite. Une fois que les deux commandes ont été reçues par le programme de contrôle, les deux commandes sont exécutées en même temps et les niveaux d’énergie de l’arène et du bot sont mis à jour pour refléter le nouvel état. Si les deux bots ont encore assez d’énergie pour continuer, le jeu passe au tour suivant. Il y aura une limite de 1000 rounds par combat pour éviter les combats, et si cette limite est atteinte, le vainqueur sera le bot le plus énergique. Si les deux bots ont la même énergie, le match est un match nul et aucun des deux ne marquera de victoire (ce serait comme s'il avait perdu tous les deux).

Les armes

Chaque bot aura à sa disposition un certain nombre d'armes:

  • Des balles perforantes. Ceux-ci parcourent 3 cases à la fois et provoquent 1 point d'énergie de dommage.
  • Missiles. Celles-ci parcourent 2 cases à la fois et provoquent 3 points de dégâts d'énergie au point d'impact et 1 point de dégâts dans toutes les cases environnantes.
  • Mines terrestres. Celles-ci tombent dans l'une des cases entourant immédiatement le bot et causent 2 points de dégâts d'énergie en marchant dessus et 1 point de dégâts en énergie à tout ce qui se trouve dans l'une des cases environnantes.
  • Pulsation éléctromagnétique. Provoque le dysfonctionnement des circuits de mouvement des deux robots pendant 2 tours, ce qui signifie qu'ils ne peuvent pas bouger. Ils peuvent cependant toujours utiliser des armes (oui, je sais que ce n’est pas réaliste, mais c’est un jeu. Ce n’est pas censé être la vraie vie). Edit: chaque déploiement EMP coûte un point d'énergie au bot qui l'utilise.

Les balles / missiles ne peuvent toucher que des robots ou des murs. Ils vont frapper n'importe quel bot qui se trouve dans l'une des cases par lesquelles ils passent. Ils disparaissent une fois qu'ils ont frappé quelque chose.

Dans tous les cas, immediately surrounding squaresdésigne les 8 carrés vers lesquels le bot pourrait se déplacer lors de son prochain déplacement - le quartier de Moore.

Les commandes

  • 0 ne fais rien.
  • N, NE, E, SE, S, SW, W, NWSont toutes les commandes de direction et déplacer le robot d' une case dans la direction donnée. Si le bot est incapable de se déplacer dans cette direction car il y a un mur ou un autre bot sur la case, le bot reste là où il se trouve. Il est prudent de se rendre dans une case contenant déjà une balle ou un missile, car on considérera que la balle / le missile est déjà en train de sortir de cette case.
  • B suivi d'un espace, puis l'une des commandes de direction tire une balle perforante dans cette direction.
  • M suivi d'un espace, puis l'une des commandes de direction tire un missile dans cette direction.
  • Lsuivi d'un espace, puis l'une des commandes de direction dépose une mine terrestre sur cette case à côté du bot. Si la case est déjà occupée par un mur ou un bot, la commande est ignorée. Si une mine terrestre tombe sur une autre, elle la fait exploser. Cela endommagerait le bot qui effectuait le largage et tout autre bot à portée de la mine d'origine.
  • P déclenche l'EMP.

Comme un seul commandement peut être donné par tour, un bot ne peut que déplacer ou tirer / déployer une arme, et non les deux à la fois.

Ordre des commandes
Le mouvement de l'un ou l'autre bot viendra toujours en premier, et tous les mouvements seront tentés deux fois pour tenir compte du fait qu'un autre bot se trouve sur le chemin, mais qu'il se déplace à l'écart.

Exemple

  • Bot1 essaie de bouger Emais Bot2 est déjà dans cette case
  • Le programme de contrôle passe à Bot2.
  • Bot2 essaie de bouger Set réussit car rien ne l' empêche .
  • Bot1 tente une seconde fois de jouer son coup. Cette fois, cela réussit et Bot1 se déplace E.

Une fois que les bots ont effectué les mouvements qu’ils souhaitent, les armes seront tirées et tous les projectiles (nouveaux et précédemment tirés) déplaceront le nombre de carrés prédéfini.

L'arène

Au début de chaque tour, le bot recevra l'état actuel du jeu comme seul argument de ligne de commande du programme:

X.....LLL.
..........
..........
..........
M.........
..........
..........
..........
..........
...B.....Y
Y 10
X 7
B 3 9 W
M 0 4 S
L 6 0
B 3 9 S
L 7 0
L 8 0

La première arène est composée de 10 lignes de 10 caractères. Il est entouré de murs non représentés. La signification des caractères est la suivante:

  • . représente un carré vide
  • Y représente votre bot.
  • X représente le bot adverse.
  • L représente une mine terrestre.
  • B représente une balle en vol.
  • M représente un missile en vol.

Vient ensuite l’énergie restante des robots, un robot par ligne. Un seul espace séparera l'identifiant du bot de son niveau d'énergie. Comme dans l'arène, Yreprésente votre bot et Xreprésente votre adversaire. Vient enfin une liste des projectiles et des mines antipersonnel, leurs positions et (le cas échéant) leurs en-têtes, encore une fois par ligne.

Le programme de contrôle

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#define NUMBOTS 2
#define BOUTSPERMATCH 5
#define ROUNDSPERBOUT 1000
#define MAXFILENAMESIZE 100
#define MAXWEAPONS 100
#define DISPLAYBOUTS true

typedef struct
{
  int x, y, energy;
  char cmd[5];
} Bot;

int getxmove(char cmd[5]);
int getymove(char cmd[5]);
int newposinbounds(int oldx, int oldy, int dx, int dy);
int directhit(Bot bot, int landmine[2]);
int landminecollision(int landmine1[2], int landmine2[2]);
int inshrapnelrange(Bot bot, int landmine[2]);
int directiontoint(char direction[5], char directions[8][3]);
void deployweapons(Bot *bot, Bot *enemy, int bullets[MAXWEAPONS][3], int missiles[MAXWEAPONS][3], int landmines[MAXWEAPONS][2], char directions[8][3]);
void cleararena(char arena[10][11]);

int main()
{
  FILE *fp;
  Bot b1, b2;
  int bot1, bot2, bot1bouts, bot2bouts;
  int bout, round, loop, totalprojectiles, dx, dy;
  char bots[NUMBOTS][MAXFILENAMESIZE]=
  {
    "./donowt              ",
    "php -f huggybot.php   "
  };
  char directions[8][3]={"N", "NE", "E", "SE", "S", "SW", "W", "NW"};
  char openstring[5000], argumentstring[4000], bot1string[6], bot2string[6];
  int matcheswon[NUMBOTS],boutswon[NUMBOTS];
  int missiles[MAXWEAPONS][3];
  int bullets[MAXWEAPONS][3];
  int landmines[MAXWEAPONS][2];
  int paralyzedturnsremaining=0;
  bool bot1moved;
  char arena[10][11];
  char projectiles[300][10];

  for(loop=0;loop<NUMBOTS;loop++)
  {
    matcheswon[loop]=0;
    boutswon[loop]=0;
  }

  srand(time(NULL));

  for(bot1=0;bot1<NUMBOTS-1;bot1++)
  {
    for(bot2=bot1+1;bot2<NUMBOTS;bot2++)
    {
      bot1bouts=bot2bouts=0;
      printf("%s vs %s ",bots[bot1],bots[bot2]);
      for(bout=0;bout<BOUTSPERMATCH;bout++)
      {
        printf("%d ",bout);
        //setup the arena for the bout
        b1.x=1;b1.y=1;
        b2.x=9;
        //b1.y=rand()%10;
        b2.y=rand()%10;
        b1.energy=b2.energy=10;
        //clear the previous stuff
        memset(missiles, -1, sizeof(missiles));
        memset(bullets, -1, sizeof(bullets));
        memset(landmines, -1, sizeof(landmines));
        for(round=0;round<ROUNDSPERBOUT;round++)
        {
          //draw the arena based on current state
          cleararena(arena);
          totalprojectiles=0;
          for(loop=0;loop<MAXWEAPONS;loop++)
          {
            if(bullets[loop][0]!= -1)
            {
              arena[bullets[loop][1]][bullets[loop][0]]='B';
              sprintf(projectiles[totalprojectiles], "%c %d %d %s\n", 'B', bullets[loop][0], bullets[loop][1], directions[bullets[loop][2]]);
              totalprojectiles+=1;
            }
            if(missiles[loop][0]!= -1)
            {
              arena[missiles[loop][1]][missiles[loop][0]]='M';
              sprintf(projectiles[totalprojectiles], "%c %d %d %s\n", 'M', missiles[loop][0], missiles[loop][1], directions[missiles[loop][2]]);
              totalprojectiles+=1;
            }
            if(landmines[loop][0]!= -1)
            {
              arena[landmines[loop][1]][landmines[loop][0]]='L';
              sprintf(projectiles[totalprojectiles], "%c %d %d\n", 'L', landmines[loop][0], landmines[loop][1]);
              totalprojectiles+=1;
            }
          }

          //send the arena to both bots to get the commands
          // create bot1's input
          arena[b1.y][b1.x]='Y';
          arena[b2.y][b2.x]='X';
          sprintf(bot1string, "Y %d\n", b1.energy);
          sprintf(bot2string, "X %d\n", b2.energy);
          strcpy(argumentstring, "'");
          strncat(argumentstring, *arena, 10*11);
          strcat(argumentstring, bot1string);
          strcat(argumentstring, bot2string);
          for(loop=0;loop<totalprojectiles;loop++)
          {
            strcat(argumentstring, projectiles[loop]);
          }
          strcat(argumentstring, "'");
          sprintf(openstring, "%s %s", bots[bot1], argumentstring);
          // send it and get the command back
          fp=popen(openstring, "r");
          fgets(b1.cmd, 5, fp);
          fflush(NULL);
          pclose(fp);

          // create bot2's input
          arena[b2.y][b2.x]='Y';
          arena[b1.y][b1.x]='X';
          sprintf(bot2string, "Y %d\n", b2.energy);
          sprintf(bot1string, "X %d\n", b1.energy);
          strcpy(argumentstring, "'");
          strncat(argumentstring, *arena, 10*11);
          strcat(argumentstring, bot2string);
          strcat(argumentstring, bot1string);
          for(loop=0;loop<totalprojectiles;loop++)
          {
            strcat(argumentstring, projectiles[loop]);
          }
          strcat(argumentstring, "'");
          sprintf(openstring, "%s %s", bots[bot2], argumentstring);
          // send it and get the command back
          fp=popen(openstring, "r");
          fgets(b2.cmd, 5, fp);
          fflush(NULL);
          pclose(fp);

          if(DISPLAYBOUTS)
          {
            arena[b1.y][b1.x]='A';
            arena[b2.y][b2.x]='B';
            printf("\033c");
            printf("Round: %d\n", round);
            printf("%s", arena);
            sprintf(bot1string, "A %d\n", b1.energy);
            sprintf(bot2string, "B %d\n", b2.energy);
            printf("%s%s", bot1string, bot2string);
          }

          //do bot movement phase
          if(paralyzedturnsremaining==0)
          {
            // move bot 1 first
            bot1moved=false;
            dx=dy=0;
            dx=getxmove(b1.cmd);
            dy=getymove(b1.cmd);
            if(newposinbounds(b1.x, b1.y, dx, dy))
            {
              if(!(b1.x+dx==b2.x) || !(b1.y+dy==b2.y))
              {
                bot1moved=true;
                b1.x=b1.x+dx;
                b1.y=b1.y+dy;
              }
            }
            // move bot 2 next
            dx=dy=0;
            dx=getxmove(b2.cmd);
            dy=getymove(b2.cmd);
            if(newposinbounds(b2.x, b2.y, dx, dy))
            {
              if(!(b2.x+dx==b1.x) || !(b2.y+dy==b1.y))
              {
                b2.x=b2.x+dx;
                b2.y=b2.y+dy;
              }
            }
            if(!bot1moved) // if bot2 was in the way first time, try again
            {
              dx=dy=0;
              dx=getxmove(b1.cmd);
              dy=getymove(b1.cmd);
              if(newposinbounds(b1.x, b1.y, dx, dy))
              {
                if(!(b1.x+dx==b2.x) || !(b1.y+dy==b2.y))
                {
                  b1.x=b1.x+dx;
                  b1.y=b1.y+dy;
                }
              }
            }
            //check for landmine hits
            for(loop=0;loop<MAXWEAPONS;loop++)
            {
              if(landmines[loop][0]!= -1)
              {
                if(directhit(b1, landmines[loop]))
                {
                  b1.energy-=2;
                  if(inshrapnelrange(b2, landmines[loop]))
                  {
                    b2.energy-=1;
                  }
                  landmines[loop][0]= -1;
                  landmines[loop][1]= -1;
                }
                if(directhit(b2, landmines[loop]))
                {
                  b2.energy-=2;
                  if(inshrapnelrange(b1, landmines[loop]))
                  {
                    b1.energy-=1;
                  }
                  landmines[loop][0]= -1;
                  landmines[loop][1]= -1;
                }
              }
            }
          }
          else
          {
            paralyzedturnsremaining-=1;
          }
          //do weapons firing phase
          if(strcmp(b1.cmd, "P")==0)
          {
            paralyzedturnsremaining=2;
            b1.energy--;
          }
          else if(strcmp(b2.cmd, "P")==0)
          {
            paralyzedturnsremaining=2;
            b2.energy--;
          }
          deployweapons(&b1, &b2, bullets, missiles, landmines, directions);
          deployweapons(&b2, &b1, bullets, missiles, landmines, directions);
          //do weapons movement phase
          int moves;
          for(loop=0;loop<MAXWEAPONS;loop++)
          {
            dx=dy=0;
            if(bullets[loop][0]!= -1)
            {
              dx=getxmove(directions[bullets[loop][2]]);
              dy=getymove(directions[bullets[loop][2]]);
              for(moves=0;moves<3;moves++)
              {
                if(newposinbounds(bullets[loop][0], bullets[loop][1], dx, dy))
                {
                  bullets[loop][0]+=dx;
                  bullets[loop][1]+=dy;
                  if(directhit(b1, bullets[loop]))
                  {
                    b1.energy-=1;
                    bullets[loop][0]= -1;
                    bullets[loop][1]= -1;
                    bullets[loop][2]= -1;
                  }
                  if(directhit(b2, bullets[loop]))
                  {
                    b2.energy-=1;
                    bullets[loop][0]= -1;
                    bullets[loop][1]= -1;
                    bullets[loop][2]= -1;
                  }
                }
                else
                {
                  bullets[loop][0]= -1;
                  bullets[loop][1]= -1;
                  bullets[loop][2]= -1;
                  dx=dy=0;
                }
              }
            }
          };
          for(loop=0;loop<MAXWEAPONS;loop++)
          {
            dx=dy=0;
            if(missiles[loop][0]!= -1)
            {
              dx=getxmove(directions[missiles[loop][2]]);
              dy=getymove(directions[missiles[loop][2]]);
              for(moves=0;moves<2;moves++)
              {
                if(newposinbounds(missiles[loop][0], missiles[loop][1], dx, dy))
                {
                  missiles[loop][0]+=dx;
                  missiles[loop][1]+=dy;
                  if(directhit(b1, missiles[loop]))
                  {
                    b1.energy-=3;
                    if(inshrapnelrange(b2, missiles[loop]))
                    {
                      b2.energy-=1;
                    }
                    missiles[loop][0]= -1;
                    missiles[loop][1]= -1;
                    missiles[loop][2]= -1;
                  }
                  if(directhit(b2, missiles[loop]))
                  {
                    b2.energy-=3;
                    if(inshrapnelrange(b1, missiles[loop]))
                    {
                      b1.energy-=1;
                    }
                    missiles[loop][0]= -1;
                    missiles[loop][1]= -1;
                    missiles[loop][2]= -1;
                  }
                }
                else
                {
                  if(inshrapnelrange(b1, missiles[loop]))
                  {
                    b1.energy-=1;
                  }
                  if(inshrapnelrange(b2, missiles[loop]))
                  {
                    b2.energy-=1;
                  }
                  missiles[loop][0]= -1;
                  missiles[loop][1]= -1;
                  missiles[loop][2]= -1;
                  dx=dy=0;
                }
              }
            }
          }
          //check if there's a winner
          if(b1.energy<1 || b2.energy<1)
          {
            round=ROUNDSPERBOUT;
          }
        }
        // who has won the bout
        if(b1.energy<b2.energy)
        {
          bot2bouts+=1;
          boutswon[bot2]+=1;
        }
        else if(b2.energy<b1.energy)
        {
          bot1bouts+=1;
          boutswon[bot1]+=1;
        }
      }
      if(bot1bouts>bot2bouts)
      {
        matcheswon[bot1]+=1;
      }
      else if(bot2bouts>bot1bouts)
      {
        matcheswon[bot2]+=1;
      }
      printf("\n");
    }
  }
  // output final scores
  printf("\nResults:\n");
  printf("Bot\t\t\tMatches\tBouts\n");
  for(loop=0;loop<NUMBOTS;loop++)
  {
    printf("%s\t%d\t%d\n", bots[loop], matcheswon[loop], boutswon[loop]);
  }
}

int getxmove(char cmd[5])
{
  int dx=0;
  if(strcmp(cmd, "NE")==0)
    dx= 1;
  else if(strcmp(cmd, "E")==0)
    dx= 1;
  else if(strcmp(cmd, "SE")==0)
    dx= 1;
  else if(strcmp(cmd, "SW")==0)
    dx= -1;
  else if(strcmp(cmd, "W")==0)
    dx= -1;
  else if(strcmp(cmd, "NW")==0)
    dx= -1;

  return dx;
}
int getymove(char cmd[5])
{
  int dy=0;
  if(strcmp(cmd, "N")==0)
    dy= -1;
  else if(strcmp(cmd, "NE")==0)
    dy= -1;
  else if(strcmp(cmd, "SE")==0)
    dy= 1;
  else if(strcmp(cmd, "S")==0)
    dy= 1;
  else if(strcmp(cmd, "SW")==0)
    dy= 1;
  else if(strcmp(cmd, "NW")==0)
    dy= -1;

  return dy;
}
int newposinbounds(int oldx, int oldy, int dx, int dy)
{
  return (oldx+dx>=0 && oldx+dx<10 && oldy+dy>=0 && oldy+dy<10);
}
int directhit(Bot bot, int landmine[2])
{
  return (bot.x==landmine[0] && bot.y==landmine[1]);
}
int landminecollision(int landmine1[2], int landmine2[2])
{
  return ((landmine1[1]==landmine2[1]) && abs(landmine1[0]==landmine2[0]));
}
int inshrapnelrange(Bot bot, int landmine[2])
{
  return (abs(bot.x-landmine[0])<2 && abs(bot.y-landmine[1])<2);
}
int directiontoint(char direction[5], char directions[8][3])
{
  int loop,returnval=8;
  for(loop=0;loop<8;loop++)
  {
    if(strcmp(directions[loop], direction)==0)
      returnval=loop;
  }
  return returnval;
}
void deployweapons(Bot *bot, Bot *enemy, int bullets[MAXWEAPONS][3], int missiles[MAXWEAPONS][3], int landmines[MAXWEAPONS][2], char directions[8][3])
{
  int loop;
  if(strlen(bot->cmd)>2)
  {
    if(bot->cmd[0]=='B')
    {
      int weaponslot=0;
      while(bullets[weaponslot][0]!= -1)
        weaponslot+=1;
      bullets[weaponslot][0]=bot->x;
      bullets[weaponslot][1]=bot->y;
      bullets[weaponslot][2]=directiontoint(bot->cmd+2, directions);
      if(bullets[weaponslot][2]>7)
      {
        // direction wasn't recognized so clear the weapon
        bullets[weaponslot][0]= -1;
        bullets[weaponslot][1]= -1;
        bullets[weaponslot][2]= -1;
      }
    }
    if(bot->cmd[0]=='M')
    {
      int weaponslot=0;
      while(missiles[weaponslot][0]!= -1)
        weaponslot+=1;
      missiles[weaponslot][0]=bot->x;
      missiles[weaponslot][1]=bot->y;
      missiles[weaponslot][2]=directiontoint(bot->cmd+2, directions);
      if(missiles[weaponslot][2]>7)
      {
        // direction wasn't recognized so clear the weapon
        missiles[weaponslot][0]= -1;
        missiles[weaponslot][1]= -1;
        missiles[weaponslot][2]= -1;
      }
    }
    if(bot->cmd[0]=='L')
    {
      int weaponslot=0;
      while(landmines[weaponslot][0]!= -1)
        weaponslot+=1;
      if(newposinbounds(bot->x, bot->y, getxmove(bot->cmd+2), getymove(bot->cmd+2)))
      {
        landmines[weaponslot][0]=bot->x+getxmove(bot->cmd+2);
        landmines[weaponslot][1]=bot->y+getymove(bot->cmd+2);

        //check for landmine hits
        for(loop=0;loop<MAXWEAPONS;loop++)
        {
          if(landmines[loop][0]!= -1)
          {
            if(landminecollision(landmines[weaponslot], landmines[loop]) && weaponslot!=loop)
            {
              if(inshrapnelrange(*bot, landmines[loop]))
              {
                bot->energy-=1;
              }
              if(inshrapnelrange(*enemy, landmines[loop]))
              {
                enemy->energy-=1;
              }
              landmines[loop][0]= -1;
              landmines[loop][1]= -1;
              landmines[weaponslot][0]= -1;
              landmines[weaponslot][1]= -1;
            }
          }
        }
      }
    }
  }
}
void cleararena(char arena[10][11])
{
  int loop;
  memset(arena, '.', 110);
  for(loop=0;loop<10;loop++)
  {
    arena[loop][10]='\n';
  }
}

Le programme de contrôle appellera votre bot depuis la ligne de commande. Pour cette raison, les programmes qui ne peuvent pas être appelés à partir de la ligne de commande seront considérés comme non valides . Je m'excuse auprès de ceux dont le langage choisi ne fonctionne pas de cette façon, mais chaque match manuellement ne serait pas pratique.

intx13 a aimablement écrit une version plus robuste du programme de contrôle avec quelques corrections de bugs que vous pouvez trouver ici .

Les suggestions d’améliorations ou de corrections de bugs du programme de contrôle sont les bienvenues.

Bots de test

Aucun des robots de test ne sera inclus dans les analyses. Ils sont juste à des fins de test.

Dudley DoNowt (C)

int main(int argc, char *argv)
{
  printf("0");
}

Ne fait rien quelle que soit la situation. Pas prévu de gagner beaucoup.

HuggyBot (PHP)

<?php
$arena=$argv[1];
list($meX, $meY)=findMe($arena);
list($oppX, $oppY)=findOpp($arena);
if($meY<$oppY)
{
  if($meX<$oppX)
    echo "SE";
  elseif($meX==$oppX)
    echo "S";
  else
    echo "SW";
}
elseif($meY==$oppY)
{
  if($meX<$oppX)
    echo "E";
  else
    echo "W";
}
else
{
  if($meX<$oppX)
    echo "NE";
  elseif($meX==$oppX)
    echo "N";
  else
    echo "NW";
}

function findMe($arena)
{
  return find("Y", explode("\n", $arena));
}

function findOpp($arena)
{
  return find("X", explode("\n", $arena));
}

function find($char, $array)
{
  $x=0;
  $y=0;
  for($loop=0;$loop<10;$loop++)
  {
    if(strpos($array[$loop], $char)!==FALSE)
    {
      $x=strpos($array[$loop], $char);
      $y=$loop;
    }
  }
  return array($x, $y);
}
?>

Essaie d'être juste à côté de l'adversaire. Vulnérable aux mines terrestres car il ne les cherche pas. Les tirs de missiles sont une tactique moins efficace pour l'adversaire lorsqu'il atteint son objectif.

Les resultats

Le pointage final sera fait après le 24 mars 2014 à 23h59 . Je ferai régulièrement des tests pour que les participants puissent voir comment leurs robots se rangent face à l’opposition actuelle.

Les entrées

Les entrées doivent inclure la source de votre bot et l'argument de ligne de commande que je devrai utiliser pour l'exécuter. Vous pouvez poster autant d’entrées que vous le souhaitez, mais chaque réponse ne doit contenir qu’un seul bot.

Important

Il semble que certaines entrées souhaitent écrire sur le disque pour conserver un certain état entre les exécutions. Ce sont de nouvelles règles concernant l'écriture sur le disque.

  • Vous pouvez modifier la source de votre propre bot. Modifier un autre bot est une tricherie et entraînera la disqualification du bot incriminé.
  • Vous pouvez écrire dans un fichier créé dans le but de stocker l’état. Ce fichier doit être stocké dans un sous-répertoire du répertoire où se trouve votre bot. Le sous-répertoire sera nommé state. L'écriture dans une autre partie du système de fichiers (autre que votre propre source) est interdite.
Gareth
la source
1
Désolé de ne pas avoir compris cela dans le bac à sable: le stock de toutes les armes est-il infini?
Jonathan Van Matre
2
@ intx13 Peut-être que le bot correspondant au bot 1 et celui correspondant au bot 2 ne devraient pas être aléatoires à chaque combat, mais choisis au hasard uniquement lors du premier combat et échangés au début de chaque combat suivant.
arshajii
2
Je pense avoir trouvé un bogue dans le code de @ intx13. Lorsque les deux bots déclenchent le PEM en même temps, je pense que les deux devraient perdre de l'énergie. Je n'ai pas lu son code, mais en le regardant, cela ne semble pas être le cas. Voir lignes 295-304 github.com/gazrogers/CodegolfBattlebotsScorer/blob/master/…
Thomas Eding
2
Un autre bug potentiel. Il semble que l'énergie des robots puisse aller en dessous de zéro. C'est correct, mais si Bot1 a -1 énergie et que Bot2 a 0 énergie, aucun ne devrait gagner.
Thomas Eding
2
Merci pour ce tournoi, @Gareth. C'était un beau défi qui m'a inspiré à explorer de nouveaux domaines de programmation. Je mettrai au défi certains de mes amis :) Bravo à tous les participants, bon jeu!
Corwin

Réponses:

14

EvilBot

un bot qui essaie d'être aussi méchant que possible

Eh bien, voici ce que j’ai: un robot Java qui essaie d’approcher le plus possible une bande circulaire de rayon 2,5 autour du centre de l’arène et de faire autant de dégâts que possible. Son modèle de mouvement est basé sur l’attribution d’une valeur de "danger" à chacune des cases voisines et sur la décision de se déplacer sur la base de ces valeurs et sur une tendance à se rapprocher d’une zone circulaire de rayon 2,5 autour du centre de la piste. J’ai utilisé certains éléments de base de la réponse de @ Geobits (par exemple, avoir un résuméBattleBotclasse et la technique d'analyse), alors merci! Je vais probablement modifier / développer ce que j'ai jusqu'à présent, même si cela se passe assez bien, comme c'est le cas pour les autres robots postés jusqu'à présent. Le code est ci-dessous. (Si quelqu'un d'autre utilise Java, n'hésitez pas à utiliser mes classes abstract / helper.)

( EvilBot.java)

import java.io.File; // debugging
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner; // debugging

class Point {

    private int x, y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int distTo(Point other) {
        return Math.max(Math.abs(x - other.x), Math.abs(y - other.y));
    }

    public double conventionalDistTo(Point other) {
        return Math.hypot(x - other.x, y - other.y);
    }

    @Override
    public boolean equals(Object other) {
        if (!(other instanceof Point))
            return false;

        Point otherPoint = (Point) other;

        return x == otherPoint.x && y == otherPoint.y;
    }

    @Override
    public int hashCode() {
        return x * (1 << Arena.ARENA_SIZE) + y;
    }

    @Override
    public String toString() {
        return "(" + x + "," + y + ")";
    }
}

interface ArenaElement {
    char getSymbol();
}

enum Projectile implements ArenaElement {

    BULLET('B', 3, 1) {

    },

    MISSILE('M', 2, 3) {

    },

    LANDMINE('L', 0, 2) {
        @Override
        public int timeUntilImpact(Point current, Point target, Direction dir) {
            return current.equals(target) ? 0 : -1;
        }
    };

    private final char symbol;
    private final int speed;
    private final int damage;

    private Projectile(char symbol, int speed, int damage) {
        this.symbol = symbol;
        this.speed = speed;
        this.damage = damage;
    }

    @Override
    public char getSymbol() {
        return symbol;
    }

    public int getSpeed() {
        return speed;
    }

    public int getDamage() {
        return damage;
    }

    public static Projectile fromSymbol(char symbol) {
        for (Projectile p : values()) {
            if (p.getSymbol() == symbol)
                return p;
        }

        return null;
    }

    public int timeUntilImpact(Point current, Point target, Direction dir) {

        final int dx = target.getX() - current.getX();
        final int dy = target.getY() - current.getY();

        if (!(dx == 0 || dy == 0 || dx == dy || dx == -dy))
            return -1;

        if (dx == 0) {
            if (dy > 0 && dir != Direction.N)
                return -1;

            if (dy < 0 && dir != Direction.S)
                return -1;
        }
        if (dy == 0) {
            if (dx > 0 && dir != Direction.E)
                return -1;

            if (dx < 0 && dir != Direction.W)
                return -1;
        }
        if (dx == dy) {
            if (dx > 0 && dir != Direction.NE)
                return -1;

            if (dx < 0 && dir != Direction.SW)
                return -1;
        }
        if (dx == -dy) {
            if (dx > 0 && dir != Direction.SE)
                return -1;

            if (dx < 0 && dir != Direction.NW)
                return -1;
        }

        int dist = target.distTo(current);

        return (dist / speed) + (dist % speed == 0 ? 0 : 1);
    }
}

enum BotType implements ArenaElement {

    ME('Y'), ENEMY('X');

    private final char symbol;

    private BotType(char symbol) {
        this.symbol = symbol;
    }

    @Override
    public char getSymbol() {
        return symbol;
    }

    public static BotType fromSymbol(char symbol) {
        for (BotType bt : values()) {
            if (bt.getSymbol() == symbol)
                return bt;
        }

        return null;
    }
}

enum EmptySpot implements ArenaElement {

    EMPTY;

    @Override
    public char getSymbol() {
        return '.';
    }

    public static EmptySpot fromSymbol(char symbol) {
        for (EmptySpot es : values()) {
            if (es.getSymbol() == symbol)
                return es;
        }

        return null;
    }
}

enum Direction {
    N, NE, E, SE, S, SW, W, NW
}

class Arena {

    public static final int ARENA_SIZE = 10;
    public static final Point center = new Point(ARENA_SIZE / 2, ARENA_SIZE / 2);

    private ArenaElement[][] arena;

    private Arena(boolean fill) {
        arena = new ArenaElement[ARENA_SIZE][ARENA_SIZE];

        if (!fill)
            return;

        for (int i = 0; i < ARENA_SIZE; i++) {
            for (int j = 0; j < ARENA_SIZE; j++) {
                arena[i][j] = EmptySpot.EMPTY;
            }
        }
    }

    public boolean inBounds(int x, int y) {
        return x >= 0 && x < ARENA_SIZE && y >= 0 && y < ARENA_SIZE;
    }

    public boolean inBounds(Point p) {
        final int x = p.getX(), y = p.getY();
        return inBounds(x, y);
    }

    public ArenaElement get(int x, int y) {
        if (!inBounds(x, y)) {
            return null; // be cautious of this
        }

        return arena[ARENA_SIZE - 1 - y][x];
    }

    public ArenaElement get(Point p) {
        return get(p.getX(), p.getY());
    }

    // note: a point is considered its own neighbor
    public List<Point> neighbors(Point p) {
        List<Point> neighbors = new ArrayList<Point>(9);

        for (int i = -1; i <= 1; i++) {
            for (int j = -1; j <= 1; j++) {
                Point p1 = new Point(p.getX() + i, p.getY() + j);

                if (get(p1) != null)
                    neighbors.add(p1);
            }
        }

        return neighbors;
    }

    public Point findMe() {
        for (int i = 0; i < ARENA_SIZE; i++) {
            for (int j = 0; j < ARENA_SIZE; j++) {
                if (get(i, j) == BotType.ME)
                    return new Point(i, j);
            }
        }

        return null;
    }

    public Point findEnemy() {
        for (int i = 0; i < ARENA_SIZE; i++) {
            for (int j = 0; j < ARENA_SIZE; j++) {
                if (get(i, j) == BotType.ENEMY)
                    return new Point(i, j);
            }
        }

        return null;
    }

    public Point impactOfRayFromPointInDirection(Point p, Direction dir) {
        int x = p.getX(), y = p.getY();

        switch (dir) {
        case N:
            y += (Arena.ARENA_SIZE - 1 - y);
            break;
        case NE: {
            int dx = (Arena.ARENA_SIZE - 1 - x);
            int dy = (Arena.ARENA_SIZE - 1 - y);

            int off = Math.max(dx, dy);

            x += off;
            y += off;
            break;
        }
        case E:
            x += (Arena.ARENA_SIZE - 1 - x);
            break;
        case SE: {
            int dx = (Arena.ARENA_SIZE - 1 - x);
            int dy = y;

            int off = Math.max(dx, dy);

            x += off;
            y -= off;
            break;
        }
        case S:
            y = 0;
            break;
        case SW: {
            int dx = x;
            int dy = y;

            int off = Math.max(dx, dy);

            x -= off;
            y -= off;
            break;
        }
        case W:
            x = 0;
            break;
        case NW: {
            int dx = x;
            int dy = (Arena.ARENA_SIZE - 1 - y);

            int off = Math.max(dx, dy);

            x -= off;
            y += off;
            break;
        }
        }

        return new Point(x, y);
    }

    private static ArenaElement fromSymbol(char symbol) {
        ArenaElement e = EmptySpot.fromSymbol(symbol);

        if (e != null)
            return e;

        e = Projectile.fromSymbol(symbol);

        if (e != null)
            return e;

        return BotType.fromSymbol(symbol);
    }

    public static Arena parse(String[] input) {
        Arena arena = new Arena(false);

        for (int i = 0; i < ARENA_SIZE; i++) {
            for (int j = 0; j < ARENA_SIZE; j++) {
                char symbol = input[i].charAt(j);

                arena.arena[i][j] = fromSymbol(symbol);
            }
        }

        return arena;
    }
}

abstract class BaseBot {

    protected static class ProjectileInfo {
        Projectile projectile;
        Point position;
        Direction direction;

        @Override
        public String toString() {
            return projectile.toString() + " " + position + " " + direction;
        }
    }

    protected Arena arena;

    protected Point myPos;
    protected int energy;

    protected Point enemyPos;
    protected int enemyEnergy;

    public List<ProjectileInfo> projectiles;

    public BaseBot(String[] args) {
        if (args.length < 1)
            return;

        String[] lines = args[0].split("\r?\n");

        projectiles = new ArrayList<ProjectileInfo>(lines.length
                - Arena.ARENA_SIZE - 2);

        arena = Arena.parse(lines);
        myPos = arena.findMe();
        enemyPos = arena.findEnemy();

        for (int i = Arena.ARENA_SIZE; i < lines.length; i++) {
            parseInputLine(lines[i]);
        }
    }

    private void parseInputLine(String line) {
        String[] split = line.split(" ");

        char c0 = line.charAt(0);
        if (c0 == 'Y') {
            energy = Integer.parseInt(split[1]);
        } else if (c0 == 'X') {
            enemyEnergy = Integer.parseInt(split[1]);
        } else {
            ProjectileInfo pinfo = new ProjectileInfo();
            pinfo.projectile = Projectile.fromSymbol(split[0].charAt(0));
            pinfo.position = new Point(Integer.parseInt(split[1]),
                    Arena.ARENA_SIZE - 1 - Integer.parseInt(split[2]));

            if (split.length > 3)
                pinfo.direction = Direction.valueOf(split[3]);

            projectiles.add(pinfo);
        }
    }

    abstract String getMove();
}

public class EvilBot extends BaseBot {

    public static final boolean DEBUG = false;

    public static void main(String... args) throws Exception {
        if (DEBUG) {
            StringBuffer input = new StringBuffer();
            Scanner scan = new Scanner(new File("a.txt"));

            while (scan.hasNextLine()) {
                input.append(scan.nextLine());
                input.append('\n');
            }

            scan.close();

            args = new String[] { input.toString() };
        }

        System.out.print(new EvilBot(args).getMove());
    }

    public EvilBot(String[] args) {
        super(args);
    }

    /*
     * Direction to p if perfectly aligned, null otherwise
     */
    private Direction getDirTo(Point p) {

        final int dx = p.getX() - myPos.getX();
        final int dy = p.getY() - myPos.getY();

        if (dx == 0) {
            return (dy > 0) ? Direction.N : Direction.S;
        }
        if (dy == 0) {
            return (dx > 0) ? Direction.E : Direction.W;
        }
        if (dx == dy) {
            return (dy > 0) ? Direction.NE : Direction.SW;
        }
        if (dx == -dy) {
            return (dy > 0) ? Direction.NW : Direction.SE;
        }

        return null;
    }

    /*
     * Direction towards p (best approximation)
     */
    private Direction getDirTowards(Point p) {
        Direction minDir = null;
        double minDist = 0;

        for (Direction dir : Direction.values()) {
            double dist = arena.impactOfRayFromPointInDirection(myPos, dir)
                    .conventionalDistTo(p);

            if (minDir == null || dist < minDist) {
                minDir = dir;
                minDist = dist;
            }
        }

        return minDir;
    }

    private boolean isEnemyCloseToWall() {
        return (enemyPos.getX() < 2 || enemyPos.getY() < 2
                || enemyPos.getX() > Arena.ARENA_SIZE - 3 || enemyPos.getY() > Arena.ARENA_SIZE - 3);
    }

    private String missileAttack() {
        return "M " + getDirTowards(enemyPos);
    }

    @Override
    public String getMove() {
        List<Point> neighbors = arena.neighbors(myPos);

        Map<Point, Double> dangerFactors = new HashMap<Point, Double>();

        for (Point neighbor : neighbors) {

            double dangerFactor = 0;

            if (arena.get(neighbor) == Projectile.LANDMINE) {
                dangerFactor += 2;
            }

            for (ProjectileInfo pi : projectiles) {

                int time = pi.projectile.timeUntilImpact(pi.position, neighbor,
                        pi.direction);

                if (time > 0) {
                    dangerFactor += ((double) pi.projectile.getDamage()) / time;
                }
            }

            dangerFactors.put(neighbor, dangerFactor);
        }

        if (dangerFactors.get(myPos) == 0) {
            // we are safe for now...

            Direction dir = getDirTo(enemyPos);
            boolean closeToWall = isEnemyCloseToWall();

            if (dir != null) {
                int dist = myPos.distTo(enemyPos);

                if (dist < Projectile.MISSILE.getSpeed() * 2) {
                    return "M " + dir;
                } else {
                    return "B " + dir;
                }
            } else if (closeToWall) {

                if (Math.random() > 0.5) // so we don't get caught in loops
                    return missileAttack();
            }
        }

        // move!
        double leastDanger = Double.POSITIVE_INFINITY;

        for (Entry<Point, Double> entry : dangerFactors.entrySet()) {
            if (entry.getValue() < leastDanger)
                leastDanger = entry.getValue();
        }

        Point moveTo = null;

        for (Entry<Point, Double> entry : dangerFactors.entrySet()) {
            if (entry.getKey().equals(myPos))
                continue;

            if (entry.getValue() == leastDanger) {

                double d1 = entry.getKey().conventionalDistTo(Arena.center);
                double d2 = moveTo == null ? 0 : moveTo
                        .conventionalDistTo(Arena.center);

                if (moveTo == null || Math.abs(d1 - 2.5) < Math.abs(d2 - 2.5)) {

                    moveTo = entry.getKey();
                }
            }
        }

        if (moveTo == null) {
            return missileAttack();
        }

        return getDirTo(moveTo).toString();
    }
}

Usage:

javac EvilBot.java
java EvilBot <input>

Remarques:

  • Actuellement, les mines terrestres ne sont pas utilisées, seulement évitées. Je ne vais probablement pas changer cela, car l'utilisation de mines antipersonnel semble faire plus de mal que de bien (du moins pour EvilBot) à en juger par quelques tests que j'ai effectués.

  • Actuellement, EMP n'est pas utilisé. J'ai essayé la stratégie d'alignement sur l'adversaire et le tir de l'EMP suivi de missiles, mais il existe quelques contre-stratégies qui gagneraient presque 100% du temps, alors j'ai décidé d'abandonner cette voie. Je pourrais explorer l’utilisation du PEM de différentes manières par la suite.

Arshajii
la source
En moyenne, EvilBot bat Straight Shooter 5-0 et Dodge Turret 2-0. Cela a beaucoup à voir avec esquiver la tourelle.
Intx13
@ intx13 Oui, j'ai aussi remarqué cela. EvilBot et Dodge Turret sont également liés avec King's Last Stand; le jeu se réduit à une boucle infinie.
Arshajii
2
@arshajii Félicitations, vous avez gagné!
Gareth
17

Rifter

Ce bot prend différentes actions en fonction de quel bot il se bat. Pour déterminer l'adversaire, il retourne son propre état et le transmet aux autres robots pour voir ce qu'ils feraient, et le compare à ce qu'ils font réellement. Une fois qu'ils ont atteint un seuil de mouvements "corrects", les tests ne sont plus testés.

Une fois qu'il connaît le bot contre lequel il se bat, il sait généralement où il se trouvera lors du prochain tour, afin de pouvoir tirer là-bas au lieu de sa position actuelle.

Bien sûr, il y a des inconvénients. La première est que les bots qui ont une activité "aléatoire" ne sont pas aussi bien détectés. Ceci est contrebalancé en utilisant la logique du dernier combat du roi lorsque l'adversaire n'est pas connu.

Cependant, si un bot est purement déterministe, il n'a aucune difficulté à déterminer de qui il s'agit. Il peut ensuite être facilement adapté à la situation en ajoutant davantage de cas dans sa logique pour chaque adversaire. Par exemple, en luttant contre Last Stand, il le coincera, se tiendra 2x1 de sorte à ne pas pouvoir se déplacer ni tirer directement, et tirera des missiles contre le mur derrière, le tuant par des éclaboussures.

Comme mes autres, il étend BattleBot.java:

import java.awt.Point;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Rifter extends BattleBot{

    String output="0";
    String state;
    String oldState = null;
    List<Rift> rifts;
    Rift chosen;
    List<Point> safe;
    Point probable;
    int round;

    final int testCount = 100;

    Rifter(String[] args) {
        super(args.length>0?args:testState);
        state = args.length>0?args[0]:testState[0];
        round = 0;
    }

    public static void main(String[] args) {
        debug = false;
        System.out.print(new Rifter(args).execute());
    }

    @Override
    String execute() {
        if(!valid)
            return "0";
        init();
        probable = getLikelyPosition();
        if(!safe.contains(yPosition) && evade())
            return output;
        if(riftShift())
            return output;
        return fallback();
    }

    boolean riftShift(){
        if(chosen==null)
            return false;
        if("P".equals(chosen.nextAction))
            return fireAt(xPosition, true);
        switch(getChosenIndex()){
        case 1:
            output = fightStand();
            break;
        case 2:
            output = fightEvil();
            break;
        default:
            output = fallback();
        }
        return output.equals("0")?false:true;
    }

    int getChosenIndex(){
        for(int i=0;i<baseBots.length;i++)
            if(chosen.bot.equals(baseBots[i]))
                return i;
        return -1;
    }

    int distanceToWall(Point pos){
        int min = Math.min(pos.x,  pos.y);
        min = Math.min(min, (arenaSize - 1) - pos.x);
        return Math.min(min, (arenaSize - 1) - pos.y);
    }

    String fightStand(){
        int wall = distanceToWall(xPosition);
        if(wall > 0 || distance(yPosition, probable) > 2){
            if(moveToward(probable, NONE))
                return output;
            if(fireAt(probable, false))
                return output;
        }

        if(probable.x==0 && probable.y==0)
            return "M NW";
        if(probable.x==arenaSize-1 && probable.y==0)
            return "M NE";
        if(probable.x==arenaSize-1 && probable.y == arenaSize-1)
            return "M SE";
        if(probable.x==0 && probable.y == arenaSize-1)
            return "M SW";
        if(probable.x==0)
            return "M W";
        if(probable.x==arenaSize-1)
            return "M E";
        if(probable.y==0)
            return "M N";
        if(probable.y==arenaSize-1)
            return "M S";

        return "M " + headings[headingToPoint(probable)];
    }

    String fightEvil(){
        if(areAligned(yPosition,xPosition)){
            if(distance(yPosition,xPosition)>3)
                if(moveToward(probable,UNALIGN))
                    return output;
            if(fireAt(probable, false))
                return output;
        }
        if(fireAt(probable, false))
            return output;
        if(moveToward(center, ALIGN))
            return output;
        return "0";
    }

    String fallback(){
        output = getOutputFrom(fallbackBots[rand.nextInt(fallbackBots.length)]);
        if(output==null)
            output="0";
        return output;
    }

    int NONE = 0;
    int ALIGN = 1;
    int UNALIGN = 2;

    boolean moveToward(Point target, int align){
        Point closest = new Point(-99,-99);
        for(Point pos : safe){
            if(pos.equals(yPosition))
                continue;
            if(distance(pos,target) < distance(closest,target)){
                if(areAligned(pos,target) && align == UNALIGN)
                    continue;
                if(!areAligned(pos,target) && align == ALIGN)
                    continue;
                closest = pos;
            }
        }

        if(isOutside(closest))
            for(Point pos : safe)
                    if(distance(pos,target) < distance(closest,target))
                        closest = pos;      
        if(distance(closest,target) > distance(yPosition,target))
            return false;
        output = headings[headingToPoint(closest)];
        return true;
    }

    boolean fireAt(Point target, boolean override){
        if(!override && !areAligned(yPosition, target))
            return false;
        int dist = distance(yPosition, target);
        if(!override && dist>3)
            return false;
        int heading = headingToPoint(target);
        output = "M ";
        if(dist > 3 || dist == 1)
            output = "B ";
        output += headings[heading];
        return true;
    }

    String getOutputFrom(String bot){
        return new Rift(bot,0).foretell(state);
    }

    boolean evade(){
        if(safe.isEmpty())
            return false;
        Point dest = null;
        for(Point pos : safe)
            if(areAligned(pos,probable))
                dest = pos;
        if(dest==null){
            output = getOutputFrom("java LastStand");
            return true;
        }
        output = headings[headingToPoint(dest)];
        return true;
    }

    Point getLikelyPosition(){
        if(chosen!=null)
            return chosen.getNextPosition(null);
        if(round > testCount)
            return xPosition;

        int[] arena = new int[arenaSize*arenaSize];
        for(Rift rift : rifts){
            Point next = rift.getNextPosition(null);
            if(!isOutside(next))
                arena[next.y*arenaSize+next.x]++;
        }
        int max = 0, index = -1;
        for(int i=0;i<arena.length;i++){
            if(arena[i] > max){
                max = arena[i];
                index = i;
            }
        }
        Point dest = new Point(index%arenaSize, index/arenaSize);
        return isOutside(dest)?xPosition:dest;
    }

    boolean areAligned(Point a, Point b){
        int x = Math.abs(a.x - b.x);
        int y = Math.abs(a.y - b.y);
        if(x==0 || y==0 || x==y)
            return true;
        return false;
    }

    void init(){
        safe = new ArrayList<Point>();
        if(spotCollision(yPosition)==null)
            safe.add(yPosition);

        for(int heading=0;heading<8;heading++){
            Point pos = nextPosition(heading, yPosition);
            if(isOutside(pos))
                continue;
            if(spotCollision(pos)==null)
                safe.add(pos);
        }

        loadBots(readState());
        updateRifts();
        writeState();
    }

    void updateRifts(){
        if(chosen == null && round < testCount)
            for(Rift rift : rifts)
                if(rift.validate(oldState))
                    rift.correct++;
    }

    Rift chooseBot(){
        double avg = 0.0;
        int highest = 0;
        Rift choice = null;

        for(Rift rift : rifts){
            avg += rift.correct;
            if(rift.correct >= highest){
                highest = rift.correct;
                choice = rift;
            }
        }
        avg /= rifts.size();
        if(choice!= null && (choice.correct > 8) && choice.correct > avg*2)
            return choice;
        else
            return null;
    }

    boolean writeState(){
        File dir = new File("state");
        dir.mkdirs();
        File file = new File("state/rifter.state");
        try {
            BufferedWriter writer = new BufferedWriter(new FileWriter(file));
            writer.write(">" + round + "\n");
            for(Rift rift : rifts)
                writer.write(":" + rift.correct + "|" + rift.bot + "\n");
            writer.write(state);
            writer.flush();
            writer.close();
        } catch (IOException e) {
            log(e.getMessage());
            return false;
        }
        return true;
    }

    List<String> readState(){
        List<String> bots = new ArrayList<String>();
        File file = new File("state/rifter.state");
        if(file.exists()){
            try {
                BufferedReader reader = new BufferedReader(new FileReader(file));
                String line;
                String oldState = "";
                line = reader.readLine();
                if(line != null && line.startsWith(">"))
                    round = Integer.valueOf(line.substring(1)) + 1;
                while((line = reader.readLine()) != null){
                    if(line.startsWith(":"))
                        bots.add(line.substring(1));
                    else 
                        oldState += line + "\n";                                            
                }
                reader.close();
                BattleBot bot = new Rifter(new String[]{oldState});
                if(isStateInvalid(bot)){
                    bots.clear();
                    oldState = "";
                    round = 0;
                }
                this.oldState = oldState;
            } catch(Exception e){
                log(e.getMessage());
                bots.clear();
                this.oldState = "";
            }
        }
        return bots.isEmpty()?Arrays.asList(baseBots):bots;
    }

    boolean isStateInvalid(BattleBot bot){
        if(!bot.valid)
            return true;
        if(distance(bot.xPosition, xPosition) > 1)
            return true;
        if(distance(bot.yPosition, yPosition) > 1)
            return true;
        if(xEnergy > bot.xEnergy || yEnergy > bot.yEnergy)
            return true;
        return false;
    }

    List<Rift> loadBots(List<String> bots){
        rifts = new ArrayList<Rift>();
        String flipped = flipState(state);
        for(String bot : bots){
            String[] tokens = bot.split("\\|");
            Rift rift;
            if(tokens.length < 2)
                rift = new Rift(bot, 0);
            else
                rift = new Rift(tokens[1], Integer.valueOf(tokens[0]));         
            rifts.add(rift);
        }
        if((chosen = chooseBot()) == null)
            if(round < testCount)
                for(Rift rift : rifts)
                    rift.nextAction = rift.foretell(flipped);
        else
            chosen.nextAction = chosen.foretell(flipped);

        return rifts;
    }

    String flipState(String in){
        String tmp = in.replaceAll("X", "Q");
        tmp = tmp.replaceAll("Y", "X");
        tmp = tmp.replaceAll("Q", "Y");
        String[] lines = tmp.split("\\r?\\n");
        tmp = lines[arenaSize];
        lines[arenaSize] = lines[arenaSize+1];
        lines[arenaSize+1] = tmp;
        String out = "";
        for(int i=0;i<lines.length;i++)
            out += lines[i] + "\n";
        return out.trim();
    }

    class Rift{
        String bot;
        String nextAction;
        String state;
        String nextState;
        int correct;

        Rift(String name, int count){
            bot = name;
            correct = count;
        }

        Point getNextPosition(String action){
            if(action==null)
                action = nextAction;
            if(action==null || action.length()<1)
                return xPosition;
            int heading = getHeading(action.split(" ")[0]);
            return nextPosition(heading, xPosition);
        }

        boolean validate(String oldState){
            boolean valid = true;
            if(oldState == null)
                return valid;
            if(oldState.split("\\r?\\n").length < 12)
                return valid;
            String action = foretell(flipState(oldState));
            if(action==null || action.length() < 1){
                log(this.bot + " : " + "invalid action");
                return valid;
            }
            BattleBot bot = new Rifter(new String[]{oldState});
            switch(action.charAt(0)){
            case 'B':
            case 'M':
            case 'L':
                valid = testShot(action, bot);
                break;
            case 'P':
            case '0':
                valid = testNothing(bot);
                break;
            default:
                valid = testMovement(action, bot);
                break;
            }
            log(this.bot + " : " + action + " : " + valid); 

            return valid;
        }

        boolean testNothing(BattleBot bot){
            if(!xPosition.equals(bot.xPosition))
                return false;
            for(Weapon weapon : weapons){
                int dist = weapon.type==LANDMINE?1:weapon.speed;
                log(dist);
                if(distance(weapon.position, bot.xPosition) != dist)
                    continue;
                int dir = weapon.heading;
                if(isHeadingExact(dir,bot.xPosition,weapon.position))
                    return false;
            }
            return true;
        }

        boolean testShot(String act, BattleBot bot){
            if(!xPosition.equals(bot.xPosition))
                return false;
            if(weapons == null)
                return false;
            String[] tokens = act.split(" ");
            char which = tokens[0].charAt(0);
            int type = which=='B'?BULLET:
                   which=='M'?MISSILE:
                              LANDMINE;

            for(Weapon weapon : weapons){
                if(weapon.type != type)
                    continue;
                int dist = weapon.type==LANDMINE?1:weapon.speed;
                log(dist);
                if(distance(weapon.position, bot.xPosition) != dist)
                    continue;
                int dir;
                if(act==null)
                    dir = weapon.heading;
                else if(tokens.length < 2)
                    return false;
                else
                    dir = getHeading(tokens[1]);
                if(isHeadingExact(dir,bot.xPosition,weapon.position))
                    return true;
            }
            return false;

        }

        boolean testMovement(String act, BattleBot bot){
            return xPosition.equals(nextPosition(getHeading(act), bot.xPosition));
        }

        String foretell(String state){
            this.state = state;
            String[] cmdRaw = bot.split(" ");
            String[] cmd = new String[cmdRaw.length+1];
            for(int i=0;i<cmdRaw.length;i++)
                cmd[i] = cmdRaw[i];
            cmd[cmd.length-1]=state;

            String out = null;
            try {
                Process p = Runtime.getRuntime().exec(cmd);
                p.waitFor();
                BufferedReader err = new BufferedReader(new InputStreamReader(p.getErrorStream()));
                String line;
                while((line = err.readLine()) != null){
                    out = line;
                }
                err.close();
                BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
                while((line = reader.readLine()) != null){
                    out = line;
                }
                reader.close();
            } catch (Exception e) {
                log(e.getMessage());
            }
            return out!=null&&out.length()<6&&out.length()>0?out:null;
        }
    }   

    String fallbackBots[] = {"node Neo-Bot.js"};

    String[] baseBots =     {
                             "java EvadeBot", 
                             "java LastStand",
                             "java EvilBot",
                             "python ReadyAimShoot.py",
                             "python DodgingTurret.py",
                             "python mineminemine.py",
                             "python StraightShooter.py",
                             "./RandomBot",
                             "./SpiralBot",
                             "ruby1.9 TroubleAndStrafe.rb",
                             "python3 CunningPlanBot.py",
                             "./CamperBot",
                             "node CentreBot.js",
                             "node Neo-Bot.js",
                             "java UltraBot",
                             "python NinjaPy.py"
    };

    static String[] testState = {".X....LLL.\n..........\n.M........\n..........\nM.........\n..........\n..........\n..........\n.Y........\n...B......\nY 10\nX 7\nM 1 2 S"};
}
Géobits
la source
Wow ... J'étais curieux de savoir combien de temps cela prendrait pour que des bots réagissent à certains bots! Comment cela se passera-t-il s'il y a quelques entrées très tardives?
lochok
Eh bien, j’ai l’intention d’ajouter d’autres robots au fur et à mesure qu’ils entrent en jeu. S'il y en a deux qui sont trop tard pour être personnalisés, la valeur par défaut fonctionne quand même assez bien.
Geobits
1
Hah, je travaille également sur un bot qui tente d'identifier le type de bot contre lequel il se bat! Maintenant, je peux le mettre à jour davantage et lui faire identifier un bot qui identifie d'autres robots! Ou peut-être vous tromper en simulant des mouvements! Muahaha!
Tom Verelst
1
@TomVerelst J'ai déjà réfléchi à plusieurs façons de contrecarrer facilement celui-ci. Je ne serai donc pas trop surpris de voir un nouveau bot le supprimer. Cela étant dit, cela fait très bien contre les robots actuellement sur le terrain, ce que je visais. Il a remporté 8/8 matches lors de mon dernier test local. Il arrive parfois que DodgeTurret soit lié, mais je ne trouve pas de motif de combat qui permette de toujours battre celui-ci. Il est donc plus facile de le laisser égaler pour nier à la fois la victoire.
Geobits
Et si ça se joue tout seul?
PyRulez
10

ReadyAimShoot

un R Bot

input <- strsplit(commandArgs(TRUE),split="\\\\n")[[1]]
arena <- do.call(rbind,strsplit(input[1:10],"")) #Parse arena
life <- as.integer(strsplit(input[11:12]," ")[[1]][2]) #Parse stats
stuff <- strsplit(input[13:length(input)]," ") #Parse elements
if(length(input)>12){ #What are they
    stuff <- strsplit(input[13:length(input)]," ")
    whatstuff <- sapply(stuff,`[`,1)
    }else{whatstuff<-""}
if(sum(whatstuff=="L")>1){ #Where are the mines
    mines <- t(apply(do.call(rbind,stuff[whatstuff=="L"])[,3:2],1,as.integer))+1
    }else if(sum(whatstuff=="L")==1){
        mines <- as.integer(stuff[whatstuff=="L"][[1]][3:2])+1
    }else{mines <- c()}
me <- which(arena=="Y",arr.ind=T) #Where am I
other <- which(arena=="X",arr.ind=T) #Where is the target
direction <- other-me #Direction of the other bot in term of indices
if(length(mines)>2){ #Direction of mines in term of indices
    dirmines <- mines-matrix(rep(me,nrow(mines)),nc=2,byrow=T)
    }else if(length(mines)==1){
        dirmines <- mines-me
        }else{dirmines<-c()}
file <- normalizePath(gsub("^--file=","",grep("^--file=",commandArgs(FALSE),v=TRUE))) #Path to this very file
f1 <- readLines(file) #Read-in this source file
where <- function(D){ #Computes direction of something in term of NSWE
    d <- ""
    if(D[2]<0) d <- paste(d,"W",sep="")
    if(D[2]>0) d <- paste(d,"E",sep="")
    if(D[1]<0) d <- paste(d,"N",sep="")
    if(D[1]>0) d <- paste(d,"S",sep="")
    d
    }
d <- where(direction) #Direction of the other bot in term of NSWE
M <- dirmines[dirmines[,1]%in%(-1:1) & dirmines[,2]%in%(-1:1),] #Which mines are next to me
if(length(M)>2){m<-apply(M,1,where)}else if(length(M)==1){m<-where(M)}else{m<-""} #Direction of close-by mines in term of NSWE
if(any(direction==0) & life >1 & !grepl("#p_fired", tail(f1,1))){
    # If aligned with target, if life is more than one 
    # and if this source file doesn't end with a comment saying the EMP was already fired
    # Fire the EMP, and leave comment on this file saying so
    action <- "P"
    f2 <- c(f1,"#p_fired2")
    cat(f2, file=file, sep="\n")
    }else if(tail(f1,1)=="#p_fired2"){
    # If EMP have been fired last turn
    # Send missile in direction of target
    # Change comment on file.
    action <- paste("M", d)
    f2 <- c(f1[-length(f1)], "#p_fired1")
    cat(f2, file=file, sep="\n")
    }else if(tail(f1,1)=="#p_fired1"){
    # If EMP was fired two turns ago
    # Send bullet and erase comment line.
    action <- paste("B", d)
    f2 <- f1[-length(f1)]
    cat(f2, file=file, sep="\n")
    }
if (any(direction==0) & life<2){
    # If aligned but life is 1 don't fire the EMP, but send missile instead
    action <- paste("M",d)
    }
if (!any(direction==0)){
    # If not aligned, try to align using shortest, landmine-free direction
    if(direction[2]<direction[1]){
        if(grepl('W',d) & !'W'%in%m){action <- 'W'}
        if(grepl('E',d) & !'E'%in%m){action <- 'E'}
        }else if(direction[2]>=direction[1]){
            if(grepl('N',d) & !'N'%in%m){action <- 'N'}
            if(grepl('S',d) & !'S'%in%m){action <- 'S'}
            }else{ #If no landmine-free direction, don't move
                action <- 0
                }
    }
cat(action,"\n")

Ce bot tente de se placer dans la même rangée ou colonne que la cible. Lorsqu'il est aligné sur la cible, il déclenche l'EMP, puis lors du tour suivant, il tire un missile en direction de la cible, puis une balle. Il devrait également être conscient de la mine environnante et les éviter, mais est complètement inconscient des balles et des missiles. Si la vie est déjà à 1, il saute l'EMP.
Pour garder une trace du moment où il déclenche l'EMP, il modifie son code source en ajoutant un commentaire à la fin du fichier ( #p_fired2dans un premier temps, il le modifie ensuite pour #p_fired1ensuite l'effacer). J'espère que le fait de savoir quand il déclenche le PEM de cette façon n'est pas trop marginal.

La ligne de commande devrait être Rscript ReadyAimShoot.R, suivie de l'argument comme dans l'exemple, au moins sur les systèmes UNIX mais probablement aussi sur Windows (je vérifierai cela quand je le testerai réellement contre les autres bots).

Edit : Puisque la version R semble rencontrer des problèmes d’analyse de l’entrée, voici une version python du même bot qui, je l’espère, fonctionne. Si un autre programmeur R voit la publication et voit ce qui ne va pas avec ce bot, n'hésitez pas à déboguer!

import sys, os

def Position(arena, element):
    y = [i for i,j in enumerate(arena) if element in arena[i]][0]
    x = arena[y].index(element)
    return (x,y)

def Direction(coord1, coord2):
    d0 = coord1[0]-coord2[0]
    d1 = coord1[1]-coord2[1]
    if d1!=0:
        a = ['N','S'][d1<0]
    else: a = ""
    if d0!=0:
        b = ['W','E'][d0<0]
    else: b = ""
    return a+b

def Shortest(coord1,coord2):
    d = abs(coord1[0]-coord2[0])-abs(coord1[1]-coord2[1])
    if d>0: a = 'EW'
    if d<=0: a = 'NS'
    return a

input = sys.argv[1].splitlines()
arena = input[0:10]
life = input[10].split(" ")
stuff = input[12:]
path = os.path.dirname(__file__)
f1 = os.path.join(path,'state','RAS')
try:
    with open(f1, 'r') as f:
        fired = int(f.read())
except:
    fired = 0

me = Position(arena, "Y")
other = Position(arena, "X")
target = Direction(me,other)
m = []
if len(stuff):
    s = [i.split(" ") for i in stuff]
    for i in s:
        if i[0]=='L': m += [(int(i[1]),int(i[2]))]


near = [(me[0]+i,me[1]) for i in range(-1,2,2)]+[(me[0],me[1]+i) for i in range(-1,2,2)]+[(5+me[0],5+me[1]) for i in range(-1,2,2)]
closeMines = [i for i in m if i in near]
dirmines = []
for j in closeMines:
    dirmines += Direction(me, j)


if target in ['N','S','E','W']:
    if int(life[1])>1 and fired==0:
        action = "P"
        with open(f1,'w') as f:
            f.write('2')
    else:
        if fired==2:
            action = "M "+target
            with open(f1,'w') as f:
                f.write('1')
        if fired==1:
            action = "B "+target
            with open(f1,'w') as f:
                f.write('0')
        if int(life[1])==1:
            action = "M "+target
else:
    s = Shortest(me,other)
    d1 = Direction((me[0],other[1]), other)
    d2 = Direction((other[0],me[1]), other)
    if s=='EW' and d1 not in dirmines:
        action = d1
    if s=='NS' and d2 not in dirmines:
        action = d2
    else:
        if d2 not in dirmines: action = d2
        if d1 not in dirmines: action = d1
        else: action = 0


sys.stdout.write(action)
planificateur
la source
Ah, vous avez proposé la même technique que celle à laquelle j'ai pensé (et mentionné à Einacio dans les commentaires). Je pense que ce sera le coureur de tête pour le moment. :-) Je vais tester quand je rentre du travail à la maison.
Gareth
1
J'ai ajouté une section à la fin de la question sur l'écriture sur disque. J'ai également effectué mon premier test - les résultats sont proches de la fin de la question. Je vais essayer de les faire assez régulièrement maintenant.
Gareth
Donc, je suppose que cela signifie que ce bot fonctionne comme il le fait maintenant avec votre marqueur? génial!
Plannapus
Il semble que. Il a facilement battu mineminemine et le RandomBot, mais a été battu par EvadeBot et votre DodingTurret.
Gareth
Je ne suis pas très surpris: parce que cela prend son temps de viser (je n'essaye pas d'être très proche de l'adversaire), je pensais que cela serait vaincu contre les dodgers. Encore un très bon résultat quand même!
Plannapus
8

Le dernier combat du roi

Une extension de mon BattleBot, cela est conçu pour lutter contre les blasters EMP. La seule manière sensée (IMO) d'utiliser EMP est de le tirer alors que vous êtes sur le même axe que l'adversaire, puis de tirer des missiles / armes vers l'adversaire coincé. Donc, je reste en dehors de l'axe :)

Si vous avez déjà eu une partie d'échecs contre un roi contre une reine, vous savez qu'une reine à elle seule ne peut pas avoir de maté , vous devez impliquer le roi. Sinon, la stratégie du roi solitaire est simple: essayez de rester en dehors de l'axe et vers le centre pour maximiser la mobilité. Si vous êtes bloqué, optez pour une impasse.

Bien sûr, il n'y a pas grand moyen de forcer une impasse ici, donc finalement vous êtes coincé sur un côté ou un coin si la reine joue à tous les niveaux de compétence. Si ce bot est jamais dans cette situation, il tire. En supposant que l'adversaire se dirige vers EMP, cela donne un avantage de dégâts d'un tour. La dernière position du roi devrait donc se dérouler correctement, à moins qu'il n'ait déjà trop peu de vie.

Oh, et si c'est déjà hors axe et à l'abri des projectiles, il ne vous reste plus qu'à faire un saut dans la direction générale de l'ennemi.

LastStand.java

import java.awt.Point;
import java.util.ArrayList;

public class LastStand extends BattleBot{

    String output = "0";
    ArrayList<Point> safeFromEnemy;
    ArrayList<Point> safeFromWeapons;
    ArrayList<Point> safeFromBoth;

    public static void main(String[] args){
        System.out.print(new LastStand(args).execute());
    }

    LastStand(String[] args){
        super(args);
        debug = false;
    }

    @Override
    String execute() {
        findSafeSpots();
        if(attack())
            return output;
        if(evade(safeFromBoth))
            return output;
        if(evade(safeFromEnemy))
            return output;

        return output;
    }

    boolean evade(ArrayList<Point> points){
        Point dest = closestToCenter(points);
        if(dest==null)
            return false;
        int heading = headingToPoint(dest);
        output = headings[heading];
        return true;
    }

    boolean attack(){
        if(safeFromEnemy.isEmpty() || safeFromBoth.contains(yPosition))
            return fire();
        return false;
    }

    Point closestToCenter(ArrayList<Point> points){
        Point closest = null;
        int dist = 15;
        for(Point pos : points){
            if(distance(center, pos) < dist){
                closest = pos;
                dist = distance(center, pos);
            }
        }
        return closest;
    }

    boolean isOnEnemyAxis(Point pos){
        int x = Math.abs(pos.x - xPosition.x);
        int y = Math.abs(pos.y - xPosition.y);
        if(x==0 || y==0 || x==y)
            return true;
        return false;
    }

    void findSafeSpots(){
        safeFromEnemy = new ArrayList<Point>();
        safeFromWeapons = new ArrayList<Point>();
        safeFromBoth = new ArrayList<Point>();

        if(!isOnEnemyAxis(yPosition))
            safeFromEnemy.add(yPosition);
        if(spotCollision(yPosition)==null)
            safeFromWeapons.add(yPosition);

        for(int heading=0;heading<8;heading++){
            Point pos = nextPosition(heading, yPosition);
            if(isOutside(pos))
                continue;
            if(!isOnEnemyAxis(pos))
                safeFromEnemy.add(pos);
            if(spotCollision(pos)==null)
                safeFromWeapons.add(pos);
        }
        for(Point pos : safeFromEnemy){
            if(safeFromWeapons.contains(pos))
                safeFromBoth.add(pos);
        }
    }

    boolean fire(){
        int heading = headingToPoint(xPosition);
        int dist = distance(xPosition, yPosition);
        if(dist>1 || yEnergy>4)
            output = "M " + headings[heading];
        else
            output = "B " + headings[heading];
        return true;
    }   
}

Pour compiler, placez dans un dossier BattleBot.javaet exécutez:

javac LastStand.java
java LastStand <arena-argument>
Géobits
la source
8

EvadeBot

Ce bot a pour priorité de rester en vie. S'il détecte des collisions entrantes, il tente de se déplacer vers un endroit sûr en vérifiant si des collisions se produisent à cet endroit. S'il n'y a pas de zones "sûres" environnantes, il reste en place et passe à l'étape suivante.

S'il n'y a pas eu de collision (ou de zones de sécurité en cas de collision), le système effectue un contrôle d'attaque. Si l'adversaire est aligné sur 8 axes, il tire 80% du temps. S'il n'est pas aligné, il tire 50% du temps dans l'en-tête le plus proche. Il choisit une arme en fonction de la distance. Si c'est proche, une mine ou une balle (selon la distance exacte et la santé relative), des missiles de loin.

S'il décide de ne pas tirer, il effectue une marche au hasard (en vérifiant à nouveau les zones sûres).

Si rien de ce qui précède n'a fonctionné, il reste en place jusqu'au prochain tour.

Il n’utilise pas EMP, et j’ai un mauvais pressentiment ReadyAimShoot, mais nous verrons comment cela se passera.


Le code est en deux morceaux. Puisqu'il est possible de créer plus d'un bot, j'ai créé une BattleBotclasse abstraite . Il inclut des fonctions d'assistance telles que la lecture de l'arène, la vérification des collisions, la gestion des en-têtes, etc. Il existe également une fonction de journal permettant de suivre ce qui se passe pendant le débogage. Si debug==false, cela n'imprimera que la sortie réelle. Si quelqu'un veut l'utiliser / l'étendre, n'hésitez pas. Ce n'est pas joli code, mais il bat l'écriture passe-partout.

BattleBot.java

import java.awt.Point;
import java.util.Random;

abstract class BattleBot {
    static boolean debug;

    Random rand;
    final String[] headings = {"N","NE","E","SE","S","SW","W","NW"};
    final int           BULLET      = 0,
                        MISSILE     = 1,
                        LANDMINE    = 2;

    final int arenaSize = 10;
    final Point center  = new Point(arenaSize/2, arenaSize/2);

    boolean valid = false;
    Weapon[] weapons;
    Point xPosition, yPosition; 
    int xEnergy, yEnergy;

    abstract String execute();

    Point nextPosition(int heading, Point from){
        if(from == null)
            from = yPosition;
        Point next = new Point(from);
        if(heading<0||heading>7)
            return next; 
        if(heading<2 || heading>6)
            next.y--;
        if(heading<6 && heading>2)
            next.y++;
        if(heading>4)
            next.x--;
        if(heading<4 && heading>0)
            next.x++;
        return next;        
    }

    boolean isHeadingExact(int heading, Point from, Point to){
        Point next = new Point(from);
        while(!isOutside(next)){
            next = nextPosition(heading, next);
            if(next.equals(to))
                return true;
        }
        return false;
    }

    int headingToPoint(Point to){
        int x = yPosition.x - to.x;
        int y = yPosition.y - to.y;
        if(x<0){
            if(y<0) return 3;
            if(y>0) return 1;
            return 2;
        }else if(x>0){
            if(y<0) return 5;
            if(y>0) return 7;
            return 6;
        }else{
            if(y<0) return 4;
            return 0;
        }
    }

    BattleBot(String[] args){
        rand = new Random();
        if(args.length < 1 || args[0].length() < arenaSize*arenaSize)
            return;
        String[] lines = args[0].split("\\r?\\n");
        if(lines.length<12)
            return;
        weapons = new Weapon[lines.length - 12];
        int wIndex = 0;
        for(int i=0;i<lines.length;i++){
            String line = lines[i];
            if(i<arenaSize){
                if(line.contains("X"))
                    xPosition = new Point(line.indexOf("X"),i);
                if(line.contains("Y"))
                    yPosition = new Point(line.indexOf("Y"),i);
            } else {
                String[] tokens = line.split(" ");
                switch(tokens[0].charAt(0)){
                case 'X':
                    xEnergy = Integer.parseInt(tokens[1]);
                    break;
                case 'Y':
                    yEnergy = Integer.parseInt(tokens[1]);
                    break;
                case 'B':
                case 'M':
                case 'L':
                    weapons[wIndex++] = new Weapon(tokens);
                    break;
                }
            }
        }
        valid = true;
    }

    int distance(Point a, Point b){
        return Math.max(Math.abs(a.x-b.x), Math.abs(a.y-b.y));
    }

    Point spotCollision(Point pos){
        for(int i=0;i<weapons.length;i++){
            Point collision = weapons[i].collisionPoint(pos);
            if(collision != null){
                log("Collision at " + collision.x + "," + collision.y + " with weapon type " + weapons[i].type);
                if(collision.equals(pos))
                    return collision;
                else if(weapons[i].type==MISSILE && distance(collision,pos) < 2)
                    return collision;
                log("Collision disregarded");
            }
        }
        return null;
    }

    boolean isOutside(Point pos){
        if(pos.x<0||pos.y<0||pos.x>=arenaSize||pos.y>=arenaSize)
            return true;
        return false;
    }

    static <T> void log(T msg){
        if(debug) System.out.println(msg);
    }

    int getHeading(String in){
        for(int i=0;i<headings.length;i++){
            if(in.equalsIgnoreCase(headings[i]))
                return i;
        }
        return -1;
    }

    class Weapon{

        final int[] speeds = {3,2,0};   
        Point position;
        int type;
        int heading;
        int speed;

        Weapon(String[] tokens){
            char which = tokens[0].charAt(0);
            type = which=='B'?BULLET:
                   which=='M'?MISSILE:
                              LANDMINE;

            speed = speeds[type];

            position = new Point(Integer.parseInt(tokens[1]), Integer.parseInt(tokens[2]));

            if(type==BULLET || type == MISSILE)
                heading = getHeading(tokens[3]);
            else
                heading = -1;
        }

        Point collisionPoint(Point pos){
            Point next = new Point(position);
            if(type==LANDMINE)
                return next;
            for(int i=0;i<speed;i++){
                next = nextPosition(heading, next);
                if(isOutside(next))
                    return next;
                if(next.equals(xPosition) || next.equals(yPosition))
                    return next;
                if(next.equals(pos))
                    return next;
            }
            return null;            
        }
    }   
}

Ce bot particulier est EvadeBot. Pour compiler / exécuter, placez-le dans un dossier avec BattleBot.javaet lancez:

javac EvadeBot.java
java EvadeBot <arena-argument>

Si vous omettez l'argument ou s'il ne parvient pas à l'analyser correctement, la "0"sortie est affichée par défaut .

EvadeBot.java

import java.awt.Point;

public class EvadeBot extends BattleBot{

    String output = "0";

    public static void main(String[] args){
        System.out.print(new EvadeBot(args).execute());
    }

    EvadeBot(String[] args) {
        super(args);
        debug = false;
    }

    @Override
    String execute() {
        if(!valid)
            return output;
        if(evade())
            return output;
        if(attack())
            return output;
        if(walk())
            return output;
        return output;
    }

    boolean evade(){
        Point collision = spotCollision(yPosition);
        if(collision!=null){
            log("Incoming! " + collision.x + "," + collision.y);
            return moveAwayFrom(collision);
        }
        return false;
    }

    boolean attack(){
        int dist = distance(yPosition, xPosition);
        int heading = headingToPoint(xPosition);
        int odds = rand.nextInt(100);

        if(isHeadingExact(heading, yPosition, xPosition)){
            if(odds<20)
                return false;
        } else {
            if(odds<50)
                return false;
        }
        log("Odds of firing " + headings[heading] + " to " + xPosition.x + "," + xPosition.y + " checked, preparing to attack.");
        if(dist==2){
            if(yEnergy > 3 || (xEnergy < 2 && yEnergy > 1)){
                output = "L " + headings[heading]; 
                return true;
            }
        }else if(dist<4){
            output = "B " + headings[heading];
            return true;
        }else{
            output = "M " + headings[heading];
            return true;
        }
        return false;
    }

    boolean walk(){
        log("Trying to random walk...");
        int heading = rand.nextInt(8);
        for(int i=0;i<8;i++,heading=(heading+1)%8){
            Point next = nextPosition(heading, yPosition);
            if(!isOutside(next) && spotCollision(next)==null){
                output = headings[heading];
                return true;
            }
        }
        return false;
    }

    boolean moveAwayFrom(Point from){
        int heading;
        if(from.equals(yPosition))
            heading = rand.nextInt(8);
        else
            heading = (headingToPoint(from) + (rand.nextBoolean()?2:6)) % 8;
        Point next = nextPosition(heading, yPosition);
        for(int i=0;i<8;i++){
            log("Checking move " + headings[heading] + " to " + next.x + "," + next.y);
            if(!isOutside(next) && spotCollision(next)==null){
                output = headings[heading];
                return true;
            }
            heading = (heading + 1) % 8;
            next = nextPosition(heading, yPosition);
        }
        return false;
    }
}
Géobits
la source
1
Agréable. Battre MineMineMine et RandomBot 5-0.
Gareth
@ Keba Pas de problème. J'allais le faire quand même; Je pense que si ça aide quelqu'un, cool. Cela pourrait être beaucoup mieux, cependant. C'est assez simple, mais je suppose qu'il a les bases.
Geobits
@Gareth j'ai corrigé un bug dans BattleBots.java. Pouvez-vous s'il vous plaît recompiler mes robots avant la prochaine exécution?
Geobits
@ Geobits Ok, va faire.
Gareth
8

Spiral Bot Alphabet Haskell

Dans un haskell alphabétisé, les commentaires sont par défaut, donc ce post est le programme. Ce bot va tirer des missiles en spirale autour de lui, ignorant les entrées. Il stocke l'état dans un fichier (qui, espérons-le, n'est pas défini par le compilateur.)

> import System.Directory (doesFileExist, createDirectoryIfMissing, setCurrentDirectory)
> import Control.Monad (unless)

Nous énumérons d’abord les actions de missiles.

> missiles = map ("M "++) $ cycle ["N", "NE", "E", "SE", "S", "SW", "W", "NW"]

Ensuite, nous allons directement dans la monade IO. Si "spiral.txt" n'existe pas, on écrit "0". Nous vérifions également le répertoire.

> main = do
>   createDirectoryIfMissing True "state"
>   setCurrentDirectory "state"
>   exists <- doesFileExist "spiral.txt"
>   unless exists $ writeFile "spiral.txt" "0"

Ensuite, nous le lisons et imprimons l’action.

>   actPos <- fmap read $ readFile "spiral.txt" :: IO Int
>   putStr $ missiles !! actPos

Et finalement, nous écrivons dans le fichier la position actuelle.

>   writeFile "spiral.txt" (show $ actPos + 1)
PyRulez
la source
1
@ Geobits J'ai ajouté une section à la fin de la question sur l'écriture sur disque. J'ai également effectué mon premier test - les résultats sont proches de la fin de la question. Je vais essayer de les faire assez régulièrement maintenant.
Gareth
Puis-je vous demander d'examiner les règles relatives à l'écriture dans des fichiers? Je demande simplement que votre fichier écrit soit dans un sous-répertoire appelé statepour éviter tout conflit accidentel avec tout autre fichier non-étatique.
Gareth
De plus, je n'ai pas inclus votre bot dans le premier test car je n'ai pas encore installé Haskell sur la machine de test. Dès qu'il sera installé, je ferai un autre test avec votre bot inclus.
Gareth
Je pense que votre nouvelle version manque une importation ou deux. Je reçois LiterateHaskell.lhs:13:5: Not in scope: 'createDirectoryIfMissing'et LiterateHaskell.lhs:14:5: Not in scope: setCurrentDirectory'` quand je tente de compiler.
Gareth
1
Ironique, mon bot est en dernier point mais a le plus de votes. Une programmation littéraire pour la victoire!
PyRulez
7

Esquivant Tourelle

un bot en python

Voici une autre tentative. Puisque ReadyAimShoot est dans l’atelier de réparation depuis un certain temps :), j’ai pensé que j’essaierais quelque chose d’autre en attendant, en utilisant Python cette fois.

import sys

def Position(arena, element):
    y = [i for i,j in enumerate(arena) if element in arena[i]][0]
    x = arena[y].index(element)
    return (x,y)

def Direction(coord1, coord2):
    d0 = coord1[0]-coord2[0]
    d1 = coord1[1]-coord2[1]
    if d1!=0:
        a = ['N','S'][d1<0]
    else: a = ""
    if d0!=0:
        b = ['W','E'][d0<0]
    else: b = ""
    return a+b

def GetPath(coord, direction):
    if direction=='N': path = [(coord[0],coord[1]-i) for i in xrange(3)]
    if direction=='S': path = [(coord[0],coord[1]+i) for i in xrange(3)]
    if direction=='E': path = [(coord[0]+i,coord[1]) for i in xrange(3)]
    if direction=='W': path = [(coord[0]-i,coord[1]) for i in xrange(3)]
    if direction=='NE': path = [(coord[0]+i,coord[1]-i) for i in xrange(3)]
    if direction=='NW': path = [(coord[0]-i,coord[1]-i) for i in xrange(3)]
    if direction=='SE': path = [(coord[0]+i,coord[1]+i) for i in xrange(3)]
    if direction=='SW': path = [(coord[0]-i,coord[1]+i) for i in xrange(3)]
    return path

def Danger(coord, stuff):
    if len(stuff):
        s = [i.split(" ") for i in stuff]
        for i in s:
            if i[0] in ['M','B']:
                path = GetPath((int(i[1]),int(i[2])),i[3])
                if coord in path:
                    return ['unsafe',path]
        return ['safe',()]
    else:
        return ['safe',()]

input = sys.argv[1].splitlines()
arena = input[0:10]
stuff = input[12:]
me = Position(arena, "Y")
center = Direction(me, (5,5))
if center != "":
    action = center
else:
    d = Danger(me,stuff)
    if d[0]=='safe':
        other = Position(arena,"X")
        target = Direction(me, other)
        action = 'M '+target
    if d[0]=='unsafe':
        escape = [(me[0]+i,me[1]) for i in range(-1,2,2)]+[(me[0],me[1]+i) for i in range(-1,2,2)]+[(5+me[0],5+me[1]) for i in range(-1,2,2)]
        esc_choice = [i for i in escape if i not in d[1]][0]
        action = Direction(me,esc_choice)

sys.stdout.write(action)

J'ai volé sans vergogne la ligne sys.argv[1].splitlines()de @Gareth mais au moins cette fois, cela signifie que je n'aurai pas de problème à analyser l'entrée.

Ce bot court au centre au début du combat, puis y reste et tire des missiles dans la direction de l'adversaire. Il essaie également d'esquiver les balles et les missiles proches s'il est sur leur chemin, puis retourne au centre avant de recommencer à tirer.

planificateur
la source
2
Je n'aime pas les noms de fonction en majuscule ici.
Keba
Cela bat mon "Straight Shooter" environ 3-2 en moyenne.
Intx13
7

Bon tireur

Ceci est un autre bot simple que vous pouvez utiliser pour les tests. Si elle a une ligne de mire directe sur l'adversaire, elle tire, sinon elle avance au hasard.

import sys
try:
  map = sys.argv[1][0:110].split()
except:
  sys.exit(1)

# Locate us and the opponent.
#
for y in range(0,10):
  for x in range(0, 10):
    if 'Y' == map[y][x]:
      me_y = y
      me_x = x
    elif 'X' == map[y][x]:
      him_y = y
      him_x = x

# If we're on a direct line with the opponent, fire a missile.
#
if me_y == him_y or me_x == him_x or abs(me_y - him_y) == abs(me_x - him_x):
  if   him_y < me_y and him_x < me_x:
    sys.stdout.write('M NW')
  elif him_y < me_y and him_x == me_x:
    sys.stdout.write('M N')
  elif him_y < me_y and him_x > me_x:
    sys.stdout.write('M NE')
  elif him_y == me_y and him_x < me_x:
    sys.stdout.write('M W')
  elif him_y == me_y and him_x > me_x:
    sys.stdout.write('M E')
  elif him_y > me_y and him_x < me_x:
    sys.stdout.write('M SW')
  elif him_y > me_y and him_x == me_x:
    sys.stdout.write('M S')
  elif him_y > me_y and him_x > me_x:
    sys.stdout.write('M SE')

# Otherwise, move randomly.
#
else:
  import random
  sys.stdout.write(random.choice(['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW']))
intx13
la source
7

néo-bot

coffeescript

Un autre bot JavaScript à ajouter au mélange. Celui-ci cible Node.js et est écrit en CoffeeScript. L'architecture découle de la foule Java avec une classe de base gérant le bottiness général et un autre fichier avec une spécialisation pour le bot à portée de main.

La stratégie principale de ce bot est de ne pas être touché par vos projectiles. Si vous n'êtes pas une menace immédiate, neo-bot commencera à tirer.

Le fichier de base shared.coffee

# entry point

deserializeBoard = (board) ->
  me = no
  you = no
  rows = board.split '\n'
  all = for i in [0...rows.length]
    row = rows[i]
    me = row: i, col: row.indexOf 'Y' if /Y/.test row
    you = row: i, col: row.indexOf 'X' if /X/.test row
    row.split ''
  throw new Error "missing player" unless me and you
  all.me = me
  all.you = you
  all

deserializeState = (state) ->
  board = deserializeBoard state[0...110]
  rest = state[110...]
    .split '\n'
    .filter (d) -> d
  if rest[0][0] is 'Y'
    board.me.health = +rest[0][2...]
    board.you.health = +rest[1][2...]
  else
    board.you.health = +rest[0][2...]
    board.me.health = +rest[1][2...]
  board.mines = []
  board.projectiles = []
  for weapon in rest[2...]
    parts = weapon[2...].split ' '
    if weapon[0] is 'L'
      board.mines.push
        row: +parts[1]
        col: +parts[0]
    else
      board.projectiles.push
        type: weapon[0]
        row: +parts[1]
        col: +parts[0]
        dir: parts[2]
  board

module.exports = bot = (handle) ->

  state = process.argv[-1...][0]
  board = deserializeState state

  move = handle board
  process.stdout.write move

Et neo-bot.coffeele code du bot.

# i know kung fu

bot = require "./shared"

board_rows = [0...10]
board_cols = [0...10]

directions = [
  'NW', 'N', 'NE'
   'W',       'E'
  'SW', 'S', 'SE'
]

direction = (a, b) ->
  if a.row < b.row
    if a.col < b.col
      "SE"
    else if a.col is b.col
      "S"
    else
      "SW"
  else if a.row is b.row
    if a.col < b.col
      "E"
    else
      "W"
  else
    if a.col < b.col
      "NE"
    else if a.col is b.col
      "N"
    else
      "NW"

move = (me, dir) ->
  row = me.row
  col = me.col
  if /N/.test dir
    row--
  if /S/.test dir
    row++
  if /W/.test dir
    col--
  if /E/.test dir
    col++
  {row, col}

clamp = (v) ->
  Math.max 0, Math.min 9, v

legal = (pos) ->
  clamp(pos.row) is pos.row and clamp(pos.col) is pos.col

randOf = (choices) ->
  i = Math.floor Math.rand * choices.length
  choices[i]

moves =
  B: 3
  M: 2

damage =
  B: 1
  M: 3

danger = (board) ->
  n = ((0 for i in [0...10]) for j in [0...10])
  for projectile in board.projectiles
    next = projectile
    for i in [0...moves[projectile.type]]
      next = move next, projectile.dir
      if projectile.type is 'M' and not legal next
        for d in directions
          schrapnel = move next, d
          if legal schrapnel
            n[schrapnel.row][schrapnel.col] += 1
      continue unless legal next
      n[next.row][next.col] += damage[projectile.type]
  for mine in board.mines
    n[mine.row][mine.col] += 2
  n

warning = (board) ->
  n = ((0 for i in [0...10]) for j in [0...10])
  for dir in directions
    p = board.you
    p = move p, dir
    continue unless legal p
    n[p.row][p.col] = damage.M - 1 # relative damage
    p = move p, dir
    continue unless legal p
    n[p.row][p.col] = damage.M
    p = move p, dir
    continue unless legal p
    n[p.row][p.col] = damage.B
  for mine in board.mines
    for dir in directions
      p = move mine, dir
      continue unless legal p
      n[p.row][p.col] += 1
  n

board_map = (map) ->
  (a) ->
    ((map a[i][j] for j in board_cols) for i in board_rows)

board_pair = (join) ->
  (a, b) ->
    ((join a[i][j], b[i][j] for j in board_cols) for i in board_rows)

boards =
  sum: board_pair (a, b) -> a + b
  scale: (n) -> board_map (a) -> a * n

chooseSafeDir = ({me, you}, lava) ->
  dirs = []
  min = +Infinity
  for dir in directions
    guess = move me, dir
    continue unless legal guess
    guess.dir = dir
    guess.damage = lava[guess.row][guess.col]
    min = guess.damage if guess.damage < min
    dirs.push guess
  dirs.sort (a, b) ->
    if a.damage < b.damage
      -1
    else if b.damage < a.damage
      1
    else
      0
  choice = randOf dirs.filter (d) ->
    d.damage < min + 1
  choice = choice or dirs[0]
  choice.dir

neo = (WARNING_FACTOR, MISSILE_FACTOR, MOVE_FACTOR) ->
  WARNING_FACTOR ?= 0.8
  MISSILE_FACTOR ?= 0.2
  MOVE_FACTOR ?= 0.1

  combine = (d, w) ->
    boards.sum d, boards.scale(WARNING_FACTOR)(w)

  shoot = ({me, you}) ->
    weapon = if Math.random() < MISSILE_FACTOR then 'M' else 'B'
    dir = direction me, you
    "#{weapon} #{dir}"

  (board) ->
    lava = combine danger(board), warning(board)

    if lava[board.me.row][board.me.col] or Math.random() < MOVE_FACTOR
      chooseSafeDir board, lava
    else
      shoot board

bot neo()

Je recommande fortement de compiler les fichiers de café en javascript avant de lancer le programme; c'est un peu plus rapide. En gros, vous voulez faire ceci:

> coffee -c *.coffee
> ./bb "java EvilBot" "node ./neo-bot.js"
couchand
la source
7

CamperBot

Ce bot reste juste où il est et tire. J'ai seulement mis en place des balles, car les autres armes pourraient nuire au bot. S'il te plaît, pardonne-moi mes terribles compétences en C;)

#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[])
{
    int direction = 0;
    char directions[][3] = {"N", "NE", "E", "SE", "S", "SW", "W", "NW"};
    srand(time(NULL));

    direction = rand() % 8;
    printf("B %s", directions[direction]);
    return 0;
}

Pas vraiment prévu de gagner beaucoup.

CommonGuy
la source
1
Bienvenue sur le site!
Jonathan Van Matre
1
Correction d'un petit bug ... pourriez-vous s'il vous plaît le recompiler pour la dernière manche? Merci :)
CommonGuy
5

Comme il n'y a pas encore d'entrées, je vais en publier une pour que vous ayez quelque chose à battre. Je te donne:

Mien! Mien! Mien!

import sys
import random
from itertools import product

def getMyPos(arena):
    x=0
    y=0
    for idx, line in enumerate(arena):
        if(line.find('Y')!= -1):
            x=line.find('Y')
            y=idx
    return [x, y]

def isNearMine(pos, badstuff):
    returnval=False
    for badthing in badstuff:
        thinglist=badthing.split(" ")
        if(thinglist[0]=='L'):
            returnval=returnval or isNear(pos, map(int, thinglist[1:3]))
    return returnval

def isNear(pos1, pos2):
    return ((abs(pos1[0]-pos2[0])<2) and (abs(pos1[1]-pos2[1])<2))

def newpos(mypos, move):
    return [mypos[0]+move[0], mypos[1]+move[1]]

def inBounds(pos):
    return pos[0]<10 and pos[0]>=0 and pos[1]<10 and pos[1]>=0

def randomSafeMove(arena, badstuff):
    mypos=getMyPos(arena)
    badsquares=[mypos] #don't want to stay still
    for badthing in badstuff:
        thinglist=badthing.split(" ")
        if(thinglist[0]=='L'):
            badsquares.append(map(int, thinglist[1:3]))
    possiblemoves=list(product(range(-1, 2), repeat=2))
    possiblemoves=[list(x) for x in possiblemoves]
    safemoves=[x for x in possiblemoves if newpos(mypos, x) not in badsquares]
    safemoves=[x for x in safemoves if inBounds(newpos(mypos, x))]
    move=random.choice(safemoves)
    return (("N S"[move[1]+1])+("W E"[move[0]+1])).strip()

def randomDropMine(arena):
    mypos=getMyPos(arena)
    badsquares=[mypos] #don't want to drop a mine under myself
    possiblemoves=list(product(range(-1, 2), repeat=2))
    possiblemoves=[list(x) for x in possiblemoves]
    possiblemoves=[x for x in possiblemoves if newpos(mypos, x) not in badsquares]
    possiblemoves=[x for x in possiblemoves if inBounds(newpos(mypos, x))]
    move=random.choice(possiblemoves)
    return "L "+(("N S"[move[1]+1])+("W E"[move[0]+1])).strip()

input=sys.argv[1].splitlines()
arena=input[0:10]
energy=input[10:12]
badstuff=input[12:]

if(isNearMine(getMyPos(arena), badstuff)):
    sys.stdout.write(randomSafeMove(arena, badstuff))
else:
    sys.stdout.write(randomDropMine(arena))

Ne fait rien de particulièrement intelligent. Dépose une mine s'il n'y en a pas dans les carrés environnants, sinon passe dans l'une des cases sûres environnantes. Peut à peine battre le HuggyBot.

Veuillez excuser le codage Naff Python.

Gareth
la source
5

Bot aléatoire

Ce bot fait juste une action aléatoire sur chaque mouvement. Il ne déclenche pas le PGE et ne regarde pas du tout la carte. La moitié du temps, c'est juste tirer dans le mur!

#include <stdio.h>
#include <sys/time.h>

void main(int argc, char **argv)
{
  char dirs[][3] = {"N", "NE", "E", "SE", "S", "SW", "W", "NW"};

  struct timeval tv;
  gettimeofday(&tv, NULL);
  srand(tv.tv_usec);

  int action = rand()%11;
  int dir = rand()%7;

  switch(action)
  {
    case 8:
      printf("B %s", dirs[dir]);
      break;

    case 9:
      printf("M %s", dirs[dir]);
      break;

    case 10:
      printf("L %s", dirs[dir]);
      break;

    default:
      printf(dirs[action]);
      break;
  }
}

Testez-le (contre lui-même) comme ci-dessous.

$ gcc random.c -o random
$ ./bb random
intx13
la source
Ça devrait être int mainvrai?
Arshajii
gcc définira le code de retour sur 0 si vous définissez main comme étant vide
intx13
Stupide gcc. void mainest BS.
Tomsmeding
5

Trouble et Strafe

Quelques représentations de Ruby dans le combat. Se déplace de haut en bas dans le mur assigné au hasard des missiles tirant sur le mur opposé. Légèrement glitchy en haut et en bas.

def getInput()
    inputlines=ARGV[0].split(/\n/)
    return [inputlines[0, 10], inputlines[10, 2], inputlines[12..-1]]
end

def getMyPos(arena)
    pos=[]
    arena.each_with_index{|str, index| pos=[str.index('Y'), index] if(!str.index('Y').nil?)}
    return pos
end

def parseProjectiles(projectiles)
    projectiles.map!{|prj| prj.split(' ')}
    missiles=projectiles.select{|prj| prj[0]=='M'}
    bullets=projectiles.select{|prj| prj[0]=='B'}
    landmines=projectiles.select{|prj| prj[0]=='L'}
    return [missiles, bullets, landmines]
end

def haveFired?(ypos, direction, projectiles)
    return projectiles.select{|prj| prj[2]==ypos.to_s && prj[3]==direction}.size>0
end

arena, botenergy, projectiles=getInput()
missiles, bullets, landmines=parseProjectiles(projectiles)

myposX=getMyPos(arena)[0]
myposY=getMyPos(arena)[1]

direction="WE"[myposX!=0 ? 0 : 1]

if haveFired?(myposY, direction, missiles)
    if myposY==0
        print "S"
    elsif myposY==9
        print "N"
    else
        if haveFired?(myposY-1, direction, missiles)
            print "S"
        elsif haveFired?(myposY+1, direction, missiles)
            print "N"
        else
            if(Random.rand(2)==0)
                print "N"
            else
                print "S"
            end
        end
    end
else
    print "M "+direction
end
Gareth
la source
5

Un noyau JavaScript

Je pensais être gentil et vous donner mon bot JS de base. Il possède toutes les fonctions nécessaires à la création d'un bot. Tout ce dont vous avez besoin est constitué d'actions à effectuer en fonction des données que cela vous donne. Pas encore terminé, je ne peux pas vraiment le tester (impossible de compiler le code d'arène).

N'hésitez pas à utiliser cela, je suis impatient de voir quelques robots JS dans le mélange.

Faire:

  • Ajouter des fonctions pour calculer l'emplacement des armes

    var stdi = WScript.StdIn;
    var stdo = WScript.StdOut;
    
    function botLog(toLog){
        var fso  = new ActiveXObject("Scripting.FileSystemObject");
        var fh = fso.CreateTextFile("./botLog.txt", 8, true);
        fh.WriteLine(toLog); 
        fh.Close(); 
    }
    
    var directions = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'];
    
    // READ ARGUMENTS AND CREATE THE ARENA
    var arena = {};
    
    arena.map = WScript.Arguments.Item(0); // Get the arena from arguments
    arena.rows = arena.map.split('\\n');
    
    
    arena.find = function(toFind){ //Find a character in the arena.
        for(var i = 0; i < 10; i++){
            if(arena.rows[i].indexOf(toFind) !== -1){
                return [arena.rows[i].search(toFind), i];
            }
        }
    };
    arena.findAtPos = function(x, y){
        return arena.rows[y].charAt(x);
    };
    
    me = {};
        me.pos = arena.find('Y');
        me.x = me.pos[0];
        me.y = me.pos[1];
        me.energy = parseInt(arena.rows[10].replace("Y ", ""));
        me.nearby = {
            N : arena.findAtPos(me.x, me.y - 1),
            NE : arena.findAtPos(me.x + 1, me.y - 1),
            E : arena.findAtPos(me.x + 1, me.y),
            SE : arena.findAtPos(me.x + 1, me.y + 1),
            S : arena.findAtPos(me.x, me.y + 1),
            SW : arena.findAtPos(me.x - 1, me.y + 1),
            W : arena.findAtPos(me.x - 1, me.y),
            NW : arena.findAtPos(me.x -1, me.y - 1),
    
            contains : function(checkFor){
                for(var j = 0; j < 8; j++){
                    if(me.nearby[j] === checkFor){
                        return true;
                    }
                }
            }
        }
    
    foe = {};
        foe.pos = arena.find('X');
        foe.x = foe.pos[0];
        foe.y = foe.pos[1];
        foe.energy = parseInt(arena.rows[11].replace("X ", ""));
    

Veuillez noter que certaines choses ici peuvent devoir être modifiées pour un autre système d'exploitation (cela ne fonctionne que sous Windows). La version de Rhino ici: http://pastebin.com/FHvmHCB8

Corwin
la source
Vote négatif et aucun commentaire? Est-ce que celui qui a voté contre cela pourrait me donner une raison? Y a-t-il une erreur dans mon code?
Corwin
Oui, le votant inférieur doit expliquer son objection ici.
Gareth
4

Center-Bot

Un bot JavaScript

Ce bot a pour objectif de pénétrer au milieu de l’arène avant de tirer des balles ou des missiles sur sa cible à chaque tour, en fonction de sa proximité. Si l'ennemi est au milieu, il ne vous reste plus qu'à tirer des balles dans la direction vague.

Je ne m'attends pas à ce que tout se passe bien, mais c'est plutôt un test, et je suis curieux de voir à quel point cela fonctionne vraiment.

    var arena = {};
var sys = require("sys");
var fs = require("fs");

arena.map = process.argv[2];
arena.rows = arena.map.split('\n');


arena.find = function(toFind){
    for(var i = 0; i < 10; i++){
            if(arena.rows[i].indexOf(toFind) !== -1){
                return [arena.rows[i].search(toFind), i];
            }
    }
};
arena.findAtPos = function(x, y){
    return arena.rows[y].charAt(x);
};

me = {};
    me.pos = arena.find('Y');
    me.x = me.pos[0];
    me.y = me.pos[1];
    me.energy = parseInt(arena.rows[10].replace("Y ", ""));

foe = {};
    foe.pos = arena.find('X');
    foe.x = foe.pos[0];
    foe.y = foe.pos[1];
    foe.energy = parseInt(arena.rows[11].replace("X ", ""));
function findFoe(){ 
    if(me.x < foe.x){
        if(me.y < foe.y){
            foe.direction = 'SE';
        }
        else if(me. y  === foe.y){
            foe.direction  = 'E';
        }
        else{
            foe.direction = 'NE';
        }
    }
    if(me.x === foe.x){
        if(me.y < foe.y){
            foe.direction = 'S';
        }
        else{
            foe.direction = 'N';
        }
    }
    if(me.x > foe.x){
        if(me.y < foe.y){
            foe.direction = 'SW';
        }
        else if(me. y  === foe.y){
            foe.direction  = 'W';
        }
        else{
            foe.direction = 'NW'
        }
    }
}

function findCentre(){
    if(me.x < 5){
        if(me.y < 5){
            centreDirection = 'SE';
        }
        else if(me.y  === 5){
            centreDirection  = 'E';
        }
        else{
            centreDirection = 'NE'
        }
    }
    if(me.x === 5){
        if(me.y < 5){
            centreDirection = 'S';
        }
        else{
            centreDirection = 'N'
        }
    }
    if(me.x > 5){
        if(me.y < 5){
            centreDirection = 'SW';
        }
        else if(me. y  === 5){
            centreDirection  = 'W';
        }
        else{
            centreDirection = 'NW'
        }
    }
}
findCentre();
findFoe();
if(me.x !== 5 && me.y !== 5){
    process.stdout.write(centreDirection);
}else{
    if(foe.x >= me.x + 2 || foe.x <= me.x - 2  || foe.y >= me.y + 2 || foe.y <= me.y - 2){
        process.stdout.write('M ' + foe.direction);
    }else process.stdout.write('B ' + foe.direction);
}

enregistrer en tant que fichier .js et exécuter avec node centrebot.js. Cela fonctionnera avec Node.js, mais vous devrez peut-être le modifier pour un autre programme, désolé!

Dans mes tests:

  • Thrashed ReadyAimShoot sans une égratignure.
  • MOSTLY l'emporte contre DencingTurret
  • A remporté le tout avec quelques égratignures des mines antipersonnel de Randombot
  • Battre Straight Shooter 9 fois sur 9, mais chaque match était serré, même si je les ai tous gagnés.

Je n'ai testé aucun des meilleurs robots java, et je ne suis pas trop confiant non plus ...

Corwin
la source
J'ai installé SpiderMonkey sur la machine de test, j'utilise donc putstr(...)à la place de your stdo.writeLine(...)et l'entrée provient de scriptArgs[0]. Après avoir fait que je devais changer \\nde \ndiviser la carte en lignes. Quand je le lance, j'obtiens une erreur car FindFoe()et findCentre()sont définis mais non appelés.
Gareth
Oops! vient de repérer une erreur! J'ai les fonctions mais ne les exécute pas réellement! Mon mauvais, je vais le changer. Merci!
Corwin
J'ai repéré une autre erreur: toutes les instructions sont inversées. Où que vous ayez un Evous devriez avoir un Wet où que vous ayez un Svous devriez avoir un N. Si vous utilisez l'exemple de saisie de la question, vous constaterez que la sortie du programme est SEune direction impossible à partir du coin inférieur droit. Je l'ai corrigé pour le prochain test.
Gareth
Bien, merci @Gareth, j'ai écrit ceci rapidement, alors je n'ai pas vraiment fait beaucoup de tests d'erreur ... Je vais réparer ça maintenant.
Corwin
3

CunningPlanBot (Python 3.3)

Ceci est complètement non testé sous l'interface actuelle ... Cela fonctionne au moins correctement avec les cartes!

C'est écrit pour Python 3.3

Ce qu'il fait:

Si en phase 1 - Si le mur et la direction se déplacent dans un mur ou dans une mine, changez de direction au hasard pour une direction autre que le mur ou la mine - Déplacez-vous dans la direction actuelle - Passez à la phase 2

Si vous êtes en phase 2 - Tirez la balle dans la direction la plus proche de l'ennemi - Passez à la phase 3

Si en phase 3 - Si aucune mine terrestre, lâchez la mine terrestre - Passez à la phase 1

Encore faut-il savoir s'il faut tirer avec un missile. De plus, je ne sais absolument pas si la mine antipersonnel fonctionne. A besoin de plus de tests demain soir.

#!/usr/bin/python
import sys
import os.path
import random
import math

def iround(x):
    return int(round(x) - .5) + (x > 0)   

currentphase = 0
currentdir = 0

#
#     4  
#   5   3  
# 6  DIR  2
#   7   1
#     0

if os.path.isfile('state/cpb'):
  statein = open('state/cpb', 'r')  
  currentdir = int(statein.read(1))
  currentphase = int(statein.read(1))
  statein.close()

Landmines = []    

#Loads the map bit. The bits we care about anyway.
line=sys.argv[1].splitlines()
for y in range(0, 10):
  for x in range(0, 10):
    if line[x][y] == "X":
      hisloc = (x, y)
    elif line[x][y] == "Y":    
      myloc = (x, y)
    elif line[x][y] == "L":
      Landmines.append((x,y))

#print(myloc[0])
#print(myloc[1])

newdir = False
if (currentphase == 0):
  if (currentdir == 7) or (currentdir == 0) or (currentdir == 1) and (myloc[1] == 9):
    newdir = True
  if (currentdir == 5) or (currentdir == 4) or (currentdir == 3) and (myloc[1] == 0):
    newdir = True
  if (currentdir == 3) or (currentdir == 2) or (currentdir == 1) and (myloc[0] == 9):
    newdir = True
  if (currentdir == 5) or (currentdir == 6) or (currentdir == 7) and (myloc[0] == 0):
    newdir = True    
  if newdir:
    newdirs = []
    #Test 0
    if (myloc[1] < 9) and not (myloc[0], myloc[1] + 1) in Landmines:
      newdirs.append(0)
    #Test 1
    if (myloc[0] < 9) and (myloc[1] < 9) and not (myloc[0] + 1, myloc[1] + 1) in Landmines:
      newdirs.append(1)
    #Test 2
    if (myloc[0] < 9) and not (myloc[0] + 1, myloc[1]) in Landmines:
      newdirs.append(2)
    #Test 3
    if (myloc[0] < 9) and (myloc[1] > 0) and not (myloc[0] + 1, myloc[1] - 1) in Landmines:
      newdirs.append(3)      
    #Test 4
    if (myloc[1] > 0) and not (myloc[0], myloc[1] - 1) in Landmines:
      newdirs.append(4)
    #Test 5
    if (myloc[0] > 0) and (myloc[1] > 0) and not (myloc[0] - 1, myloc[1] - 1) in Landmines:
      newdirs.append(5)    
    #Test 6
    if (myloc[0] > 0) and not (myloc[0] - 1, myloc[1] ) in Landmines:
      newdirs.append(6)      
    #Test 7
    if (myloc[0] > 0) and (myloc[1] > 9) and not (myloc[0] - 1, myloc[1] + 1) in Landmines:
      newdirs.append(7)     
    if len(newdirs) == 0:
      if currendir == 0: currentdir = 4
      elif currendir == 1: currentdir = 5
      elif currendir == 2: currentdir = 6
      elif currendir == 3: currentdir = 7
      elif currendir == 4: currentdir = 0
      elif currendir == 5: currentdir = 1
      elif currendir == 6: currentdir = 2
      elif currendir == 7: currentdir = 3
    else:
      currentdir = random.SystemRandom().choice(newdirs)
  if currentdir == 0: print ("S", end="")
  elif currentdir == 1: print ("SE", end="")
  elif currentdir == 2: print ("E", end="")
  elif currentdir == 3: print ("NE", end="")
  elif currentdir == 4: print ("N", end="")
  elif currentdir == 5: print ("NW", end="")
  elif currentdir == 6: print ("W", end="")
  elif currentdir == 7: print ("SW", end="")

elif (currentphase == 1):
  dx = (myloc[0] - hisloc[0])
  dy = (myloc[1] - hisloc[1])
  distance = math.pow(dx*dx+dy*dy, 0.5)
  angle = int(iround(math.degrees(math.atan2(dx, -dy)) / 45) ) % 8
  if angle == 5: print ("B S", end="")
  elif angle == 1: print ("B SE", end="")
  elif angle == 2: print ("B E", end="")
  elif angle == 3: print ("B NE", end="")
  elif angle == 4: print ("B N", end="")
  elif angle == 5: print ("B NW", end="")
  elif angle == 6: print ("B W", end="")
  elif angle == 7: print ("B SW", end="") 

elif (currentphase == 2):
  if not (myloc in Landmines): print ("L", end="")

currentphase = (currentphase + 1) % 3    

stateout = open ('state/cpb', 'w')
stateout.write(str(currentdir))
stateout.write(str(currentphase))
stateout.close()
lochok
la source
2
Un couple de choses que je devais faire pour que cela fonctionne avec le programme de correction: j'avais l'habitude sys.argv[1].splitlines()de saisir l'entrée de la ligne de commande, puis de l'utiliser line[x][y]dans le bloc suivant; ajouté end=""aux commandes d'impression pour se débarrasser de la nouvelle ligne qui déroute le marqueur; changé l'état d'écrire dans un fichier du staterépertoire plutôt que statelui-même.
Gareth
Eek! Mes excuses. C'était plus tard dans la nuit alors j'aurais probablement dû l'envoyer. Je vais l'obtenir conforme aux spécifications dès que possible!
Lochok
Pas de problème, je vais utiliser mes correctifs pour tous les tests de scoring jusqu'à ce que vous l'examiniez.
Gareth
J'ai appliqué les mêmes correctifs mais je reçois 'Py_Initialise: impossible d'initialiser les flux standard sys'. Toute chance que je puisse saisir votre version de la source pour voir si elle fait la même chose?
lochok
1
J'ai ajouté ma version de la source en tant que modification à votre message (cela semblait être le moyen le plus simple). Il suffit de revenir en arrière lorsque vous avez saisi la source.
Gareth
3

UltraBot

Un bot Java qui calcule le danger pour chaque champ environnant. Si un champ environnant est moins dangereux que le champ actuel, le bot s'y déplace (ou un autre champ également dangereux). S'il n'y a pas de champ moins dangereux, le bot tire (missiles si le bot ennemi est loin, balles si le bot ennemi est proche). J'ai pris un code du BattleBot (merci!).

import java.awt.Point;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;

public class UltraBot {
    private static final int arenaSize = 10;
    private static ArrayList<Weapon> weapons = new ArrayList<Weapon>();
    private static Bot me;
    private static Bot enemy;

    public static void main(String args[]) {
        Direction suggestedMove;
        readInput(args[0]);
        suggestedMove = suggestedMove();

        if (suggestedMove != Direction.STAY) {
            System.out.print(suggestedMove.name());
            return;
        }

        System.out.print(shootCmd());
    }

    public static void readInput(String args) {
        String[] lines = args.split("\\r?\\n");

        for(int i=0;i<lines.length;i++){
            String line = lines[i];
            if(i<arenaSize){
                if(line.contains("X"))
                    enemy = new Bot(new Field(line.indexOf("X"),i));
                if(line.contains("Y"))
                    me = new Bot(new Field(line.indexOf("Y"),i));
            } else {
                String[] tokens = line.split(" ");
                switch(tokens[0].charAt(0)){
                case 'X':
                    enemy.setLife(Integer.parseInt(tokens[1]));
                    break;
                case 'Y':
                    me.setLife(Integer.parseInt(tokens[1]));
                    break;
                default:
                    weapons.add(new Weapon(tokens));
                    break;
                }
            }
        }
    }

    public static Direction suggestedMove() {
        Map<Direction, Integer> surrFields = new HashMap<Direction, Integer>();
        Random rand = new Random();

        //calculate danger for all surrounding fields
        for(Direction direction : Direction.values()) {
            Field currField = me.getPos().incPos(direction, 1);
            surrFields.put(direction, currField.calcDanger(weapons, enemy));
        }

        int currDanger = surrFields.get(Direction.STAY);
        Direction currDirection = Direction.STAY;

        for (Entry<Direction, Integer> e : surrFields.entrySet()) {
            //always move if better field found
            if (e.getValue() < currDanger) {
                currDanger = e.getValue();
                currDirection = e.getKey();
            }
            //move sometimes if equal danger field found
            else if(e.getValue() == currDanger && rand.nextInt(3) == 1) {
                if (currDanger != 0 || rand.nextInt(15) == 1) {
                    currDanger = e.getValue();
                    currDirection = e.getKey();
                }
            }
        }
        return currDirection;
    }

    public static String shootCmd() {
        WeaponType type = WeaponType.M;

        if(me.getPos().isNear(enemy.getPos(), 3)) {
            type = WeaponType.B;
        }

        return type.name() + " " + me.shootDirection(enemy);
    }
}

class Bot {
    private Field pos;
    private int life;

    public Bot(Field pos) {
        this.pos = pos;
    }

    public void setLife(int life) {
        this.life = life;
    }

    public Field getPos() {
        return pos;
    }

    public int getLife() {
        return life;
    }

    public String shootDirection(Bot other) {
        Random rand = new Random();
        Direction direction = Direction.S;
        if (getPos().getX() >= other.getPos().getX() && getPos().getY() >= other.getPos().getY()) {
            switch(rand.nextInt(5)) {
                case 0: direction =  Direction.N; break;
                case 1: direction = Direction.W; break;
                default: direction = Direction.NW; break;
            }
        }
        else if (getPos().getX() <= other.getPos().getX() && getPos().getY() >= other.getPos().getY()) {
            switch(rand.nextInt(3)) {
                case 0: direction = Direction.N; break;
                case 1: direction = Direction.E; break;
                default: direction = Direction.NE; break;
            }
        }
        if (getPos().getX() >= other.getPos().getX() && getPos().getY() <= other.getPos().getY()) {
            switch(rand.nextInt(3)) {
                case 0: direction = Direction.S; break;
                case 1: direction = Direction.W;break;
                default: direction = Direction.SW;break;
            }
        }
        if (getPos().getX() <= other.getPos().getX() && getPos().y <= other.getPos().y) {
            switch(rand.nextInt(3)) {
                case 0: direction = Direction.S; break;
                case 1: direction = Direction.E; break;
                default: direction = Direction.SE; break;
            }
        }
        return direction.name();
    }
}

enum Direction {
    N(0, -1), NE(1, -1), E(1, 0), SE(1, 1), S(0, 1), SW(-1, 1), W(-1, 0), NW(-1,-1), STAY(0,0);

    public final int offsetX;
    public final int offsetY;

    Direction(int offsetX, int offsetY) {
        this.offsetX = offsetX;
        this.offsetY = offsetY;
    }
}

enum WeaponType {
    B(1, 3), M(3, 2), L(2, 0);

    public final int dmg;
    public final int speed;

    WeaponType(int dmg, int speed) {
        this.dmg = dmg;
        this.speed = speed;
    }
}

class Weapon {
    private WeaponType type;
    private Direction direction;
    private Field pos;

    public Weapon(String[] tokens) {
        this.type = WeaponType.valueOf(tokens[0]);
        this.pos = new Field(Integer.parseInt(tokens[1]), Integer.parseInt(tokens[2]));
        if(type != WeaponType.L) {
            this.direction = Direction.valueOf(tokens[3]);
        }
    }

    public int getDanger(Field dest) {

        if (dest.isOutside()) {
            return 99;
        }

        if (type == WeaponType.L) {
            return dest.equals(pos) ? type.dmg * 3 : 0; // stepped on landmine
        }

        for (int i = 1; i <= type.speed; i++) {
            Field newPos = pos.incPos(direction, i);

            if (dest.equals(newPos)) {
                return type.dmg * 3; // direct hit with missile or bullet
            }
        }

        return 0;
    }
}

class Field extends Point{

    public Field(int x, int y) {
        super(x,y);
    }

    // as it tries to stay off walls and enemy, it doesn't need to calc splash dmg

    public int calcDanger(ArrayList<Weapon> weapons, Bot enemy) {
        int danger = 0;

        // is near wall
        if (this.getX() == 0 || this.getX() == 9)
            danger++;
        if (this.getY() == 0 || this.getY() == 9)
            danger++;

        for (Weapon weapon : weapons) {
            danger += weapon.getDanger(this);
        }

        // near bot
        if (this.isNear(enemy.getPos(), 2)) {
            danger++;
        }

        return danger;
    }

    public Boolean isOutside() {
        if (this.getX() > 9 || this.getY() > 9 || this.getX() < 0 || this.getY() < 0) {
            return true;
        }
        return false;
    }

    public Boolean isNear(Field dest, int distance) {
        int dx = (int)Math.abs(dest.getX() - this.getX());
        int dy = (int)Math.abs(dest.getY() - this.getY());

        if (dx <= distance || dy <= distance) {
            return true;
        }
        return false;
    }

    public Field incPos(Direction direction, int step) {
        return new Field((int)this.getX() + (direction.offsetX * step), 
                (int)this.getY() + (direction.offsetY * step));
    }
}

Ce bot est extrêmement difficile à toucher, mais pas très bon pour tirer sur l'ennemi… Je m'attends toujours à ce qu'il soit meilleur que mon précédent CamperBot.

CommonGuy
la source
Juste essayé de le compiler et jeté un tas d'erreurs. On dirait qu'il manque des imports?
Gareth
Beaucoup d'erreurs sur l'accès privé aussi:UltraBot.java:...: x has private access in Point
Gareth
Ups, j'ai oublié les importations ...
Correction
1
D'accord merci. Cela fonctionne sur ma machine maintenant.
Gareth
2

NinjaPy

Une soumission de dernière minute en python (non testée mais qui, espérons-le, fonctionnera). L'idée est qu'il avance vers l'adversaire tout en restant dans son angle mort. Quand il est assez proche (à 3 cellules de distance), il se place dans la diagonale de l'adversaire et tire un missile.

import sys

def position(arena, element):
    y = [i for i,j in enumerate(arena) if element in arena[i]][0]
    x = arena[y].index(element)
    return (x,y)

def distance(other):
    dM = [[0 for x in range(10)] for y in range(10)]
    for i in range(len(dM)):
        for j in range(len(dM[0])):
            dM[i][j] = max([abs(other[0]-i),abs(other[1]-j)])
    return dM

def direction(coord1, coord2):
    d0 = coord1[0]-coord2[0]
    d1 = coord1[1]-coord2[1]
    if d1!=0:
        a = ['N','S'][d1<0]
    else: a = ""
    if d0!=0:
        b = ['W','E'][d0<0]
    else: b = ""
    return a+b

def getPath(coord, aim, speed):
    d = {'N': (0,-1), 'S':(0,1), 'E':(1,0), 'W':(-1,0), 'NW':(-1,-1), 'NE':(1,-1), 'SW':(-1,1), 'SE':(1,1)}
    D = d[aim]
    path = [(coord[0]+D[0]*i, coord[1]+D[1]*i) for i in range(speed+1)]
    return path

def dangerMap(stuff,other):
    dM = [[0 for x in range(10)] for y in range(10)]
    surroundings = [(other[0]+i,other[1]+j) for i in range(-2,3) for j in range(-2,3)]
    for i in range(len(dM)):
        for j in range(len(dM[0])):
            if i == other[0] : dM[i][j] = 1
            if j == other[1] : dM[i][j] = 1
            if (i,j) in [(other[0]+k, other[1]+k) for k in range(-10,11)]: dM[i][j] = 1
            if (i,j) in [(other[0]-k, other[1]+k) for k in range(-10,11)]: dM[i][j] = 1
    for j in surroundings:
        dM[j[0]][j[1]] = 2
    if len(stuff):
        s = [i.split(" ") for i in stuff]
        for i in s:
            if i[0]=='L':
                g = [(int(i[1]),int(i[2]))]
            if i[0]=='M':
                g = getPath((int(i[1]),int(i[2])),i[3],2)
            if i[0]=='B':
                g = getPath((int(i[1]),int(i[2])),i[3],3)
            for j in g:
                dM[j[0]][j[1]] = 2
    return dM

input = sys.argv[1].splitlines()
arena = input[0:10]
stuff = input[12:]
me = position(arena, "Y")
other = position(arena,"X")
distOther = distance(other)
distMe = distance(me)
dangM = dangerMap(stuff,other)
if distOther[me[0]][me[1]] > 3:
    surroundings = [(i,j) for i in range(10) for j in range(10) if distMe[i][j]==1]
    choice = [k for k in surroundings if dangM[k[0]][k[1]] == 0]
    if len(choice)==0: choice = [k for k in surroundings if dangM[k[0]][k[1]] == 1]
    if len(choice)>1:
        K = []
        for i in choice: K += [distOther[i[0]][i[1]]]
        choice = [choice[k] for k in range(len(choice)) if K[k] == min(K)]
    action = direction(me,choice[0])
else:
    diag = [(other[0]+i, other[1]+i) for i in [-2,2]]+[(other[0]-i, other[1]+i) for i in [-2,2]]
    if me in diag:
        action = 'M '+direction(me,other)
    else:
        distDiag = []
        for i in diag:
            distDiag += [distMe[i[0]][i[1]]]
        choice = [diag[k] for k in range(len(diag)) if distDiag[k] == min(distDiag)]
        action = direction(me,choice[0])

sys.stdout.write(action)
planificateur
la source
Désolé pour l'entrée tardive: j'étais à une réunion pour la plupart de la semaine dernière.
Plannapus