배틀 봇 : 토너먼트


69

결과는 대회가 끝났습니다.
승자는 arshajii의 EvilBot 이 14 승, Neo-Bot보다 13 승, CentreBot 및 LastStand는 각각 11 승입니다.

마지막 경기에서 얻은 점수

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)

이것은 도전입니다. 다른 봇보다 더 많은 봇을 이길 수있는 봇을 작성하는 것이 목표입니다.

게임

봇은 자신의 에너지가 0으로 감소되기 전에 상대의 에너지를 10에서 0으로 낮추는 작업으로 10x10 경기장에서 한 번에 서로 2에 대해 움푹 패입니다.

각 경기는 5 번의 시합으로 구성됩니다. 경기의 승자가 가장 많은 시합의 승자입니다. 경기 승리 및 한판 승의 총 횟수는 제어 프로그램에 의해 저장되며 대회의 전체 우승자를 결정하는 데 사용됩니다. 승자는 큰 녹색 진드기와 대중의 숭배를받습니다.

각 시합은 여러 차례 진행됩니다. 각 라운드의 시작 부분에서 경기장의 현재 상태가 각 봇에 제공되고 봇은 다음에 무엇을할지 결정하는 명령으로 응답합니다. 제어 프로그램이 두 명령을 모두 수신하면 두 명령이 동시에 실행되고 경기장 및 봇 에너지 레벨이 새로운 상태를 반영하도록 업데이트됩니다. 두 봇에 여전히 충분한 에너지가 있다면 게임은 다음 라운드로 진행됩니다. 한 번에 한 번만 경기를하지 않기 위해 한 번에 한 라운드 당 1000 라운드가 있으며,이 한도에 도달하면 가장 많은 에너지를 가진 봇이 승자가됩니다. 두 봇이 모두 같은 에너지를 가지고 있다면 한판 승부가 무승부이며 어느 봇도 승점을 얻지 못합니다 (두 잃어버린 것처럼).

무기

각 봇은 여러 가지 무기를 사용할 수 있습니다.

  • 장갑 관통 총알. 이들은 한 번에 3 칸씩 이동하여 1의 에너지 피해를 입 힙니다.
  • 미사일. 이것들은 한 번에 2 칸씩 이동하며 충격 지점에서 3의 에너지 피해를 입히고, 즉시 인접한 모든 칸에서 1의 피해를줍니다.
  • 지뢰. 이들은 봇을 바로 둘러싼 사각형 중 하나에 떨어 뜨려 밟으면 2의 에너지 피해 지점과 1 개의 에너지가 바로 인접한 사각형 중 하나에 서있는 데미지를 입 힙니다.
  • 전자기 펄스. 두 봇의 이동 회로가 2 턴 동안 오작동을 일으켜 움직일 수 없습니다. 그러나 그들은 여전히 ​​무기를 배치 할 수 있습니다 (예, 그것이 현실적이지는 않지만 게임이라는 것을 알고 있습니다. 현실이 아니어야합니다). 편집 : 각 EMP 배포는이를 사용하는 봇에 대해 하나의 에너지 포인트가 필요합니다.

총알 / 미사일은 봇이나 벽에만 영향을 줄 수 있습니다. 그들은 그들이 여행하는 사각형 중 하나에있는 모든 봇을 칠 것입니다. 일단 무언가를 치면 사라집니다.

모든 경우 immediately surrounding squares에 봇이 다음 이동시 무어 지역으로 이동할 수있는 8 개의 사각형을 의미합니다.

명령

  • 0 아무것도하지 마세요.
  • N, NE, E, SE, S, SW, W, NW모든 방향의 명령입니다 주어진 방향으로 봇 하나의 사각형을 이동합니다. 정사각형에 벽이나 다른 봇이있어 봇이 해당 방향으로 이동할 수없는 경우 봇은 원래 위치에 유지됩니다. 총알 / 미사일이 이미 해당 사각형을 벗어나는 것으로 간주되므로 이미 총알이나 미사일이 포함 된 사각형으로 이동하는 것이 안전합니다.
  • B 다음에 공백이오고 방향 명령 중 하나가 해당 방향으로 갑옷 관통 탄환을 발사합니다.
  • M 다음에 공백이 오면 방향 명령 중 하나가 해당 방향으로 미사일을 발사합니다.
  • L다음에 공백이오고 방향 명령 중 하나가 봇 옆의 광장에 지뢰를 떨어 뜨립니다. 사각형이 이미 벽이나 봇에 의해 점유되어 있으면 명령이 무시됩니다. 지뢰가 다른 지뢰에 떨어지면 폭발합니다. 이렇게하면 떨어 뜨리는 로봇과 원래 지뢰 범위 내의 다른 로봇이 손상됩니다.
  • P EMP를 시작합니다.

라운드 당 하나의 명령 만 주어질 수 있기 때문에 봇은 무기를 동시에 이동하거나 발사 / 배포 할 수 있으며 동시에 둘 다 수행 할 수는 없습니다.

명령 순서
어느 한 쪽 로봇의 움직임이 항상 우선하며, 모든 다른 움직임은 다른 로봇이 방해가되지만 방해가되는 것을 설명하기 위해 두 번 시도됩니다.

  • 봇 1은 움직이려고 E하지만 봇 2는 이미 그 광장에 있습니다.
  • 제어 프로그램이 Bot2로 이동합니다.
  • Bot2는 S아무 것도 없기 때문에 움직이고 성공합니다.
  • Bot1은 이동을 시도합니다. 이번에는 성공하고 Bot1이 움직 E입니다.

봇이 원하는 이동을하면 무기가 발사되고 모든 발사체 (신규 및 이전에 발사)가 사전 정의 된 수의 제곱을 이동합니다.

경기장

각 라운드가 시작될 때 봇은 프로그램의 유일한 명령 줄 인수로 현재 플레이 상태를받습니다 :

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

경기장은 10 줄의 10 줄로 구성됩니다. 표시되지 않은 벽으로 둘러싸여 있습니다. 문자의 의미는 다음과 같습니다.

  • . 빈 사각형을 나타냅니다
  • Y 당신의 봇을 나타냅니다.
  • X 상대 봇을 나타냅니다.
  • L 지뢰를 나타냅니다.
  • B 비행 중에 총알을 나타냅니다.
  • M 비행 중 미사일을 나타냅니다.

그 다음에는 봇의 남은 에너지가 한 줄에 하나씩 있습니다. 하나의 공간 만 봇 식별자를 에너지 수준과 분리합니다. 경기장과 마찬가지로 Y봇을 X나타내며 상대를 나타냅니다. 마지막으로 발사체와 지뢰, 그들의 위치 및 (필요한 경우) 표제의 목록을 한 줄에 하나씩 다시 제공합니다.

제어 프로그램

#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';
  }
}

제어 프로그램은 명령 줄에서 봇을 호출합니다. 이러한 이유로 명령 행에서 호출 할 수없는 프로그램은 유효하지 않은 것으로 간주됩니다 . 선택한 언어가 그런 식으로 작동하지 않는 사람들에게 사과하지만 각 경기를 수동으로 수행하는 것은 비현실적입니다.

intx13여기에서 찾을 수있는 몇 가지 버그 수정과 함께보다 강력한 버전의 제어 프로그램을 친절하게 작성했습니다 .

제어 프로그램의 개선 또는 버그 수정에 대한 제안을 환영합니다.

테스트 봇

없음 테스트 봇은 점수 실행에 포함되지 않습니다. 그들은 단지 테스트 목적입니다.

더들리 도노 트 (C)

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

상황에 관계없이 아무 것도하지 않습니다. 많이 이길 것으로 예상되지 않습니다.

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);
}
?>

상대방 바로 옆에 가려고합니다. 지뢰를 찾지 않기 때문에 지뢰에 취약합니다. 발사 미사일이 목표를 달성 할 때 상대에게 덜 효과적인 전술을 만듭니다.

결과

최종 채점은 2014 년 3 월 24 일 23:59 이후 실시됩니다 . 참가자들이 자신의 봇이 현재 반대에 어떻게 쌓이는 지 확인할 수 있도록 테스트 실행을 정기적으로 실행합니다.

출품작

출품작에는 봇의 소스와이를 실행하기 위해 사용해야하는 명령 줄 인수가 포함되어야합니다. 원하는만큼 다른 게시물을 게시 할 수 있지만 각 답변에는 하나의 봇만 포함되어야합니다 .

중대한

실행 중 일부 상태를 유지하기 위해 일부 항목이 디스크에 쓰려고하는 것 같습니다. 디스크 쓰기와 관련된 새로운 규칙입니다.

  • 자신의 봇 소스를 수정할 수 있습니다. 다른 봇을 수정하면 부정 행위가되며 해당 봇이 실격 처리됩니다.
  • 상태 저장을 위해 작성된 파일에 쓸 수 있습니다. 이 파일은 봇이 위치한 디렉토리의 하위 디렉토리에 저장해야합니다. 서브 디렉토리 이름은으로 지정 state됩니다. 파일 시스템의 다른 부분 (자체 소스 이외의)에 쓰는 것은 허용되지 않습니다.

1
샌드 박스에서 이것을 발견하지 못해서 죄송합니다 : 모든 무기의 공급이 무한합니까?
Jonathan Van Matre

2
@ intx13 아마도 봇 1에 해당하는 봇과 봇 2에 해당하는 봇은 모든 한판 승부마다 무작위 일 필요는 없지만, 첫 번째 한판 승부에서만 무작위로 선택되어 다음 각 한판 승부 시작시 스왑됩니다.
arshajii

2
@ intx13의 코드에서 버그를 발견했다고 생각합니다. 두 봇이 동시에 EMP를 발사하면 둘 다 에너지를 잃어야한다고 생각합니다. 나는 그의 코드를 실행하지 않았지만 그것을 보았을 때, 이것은 사실이 아닙니다. 라인 295-304 참조 github.com/gazrogers/CodegolfBattlebotsScorer/blob/master/…
Thomas Eding

2
또 다른 잠재적 인 버그. 봇 에너지는 0보다 낮을 수 있습니다. 괜찮습니다. 그러나 Bot1에 -1 에너지가 있고 Bot2에 0 에너지가 있으면 어느 쪽도 승리하지 않아야합니다.
Thomas Eding

2
@Gareth 토너먼트에 감사드립니다. 좋은 도전이었고 새로운 프로그래밍 영역을 탐구하도록 영감을주었습니다. 내 친구 중 일부에 도전 할 것입니다. :) 모든 참가자들에게 좋은 게임입니다!
Corwin

답변:


14

이블 봇

가능한 한 악하려고하는 봇

여기에 내가 가진 것이 있습니다 : 가능한 한 경기장의 중심 주위에 반경 2.5의 원형 스트립을 상대방 과 가깝게하려고 노력하고 가능한 한 많은 피해를 입히는 Java 봇 . 이동 패턴은 인접한 각 사각형에 "위험"값을 할당하고 이러한 값 기반으로 이동하기로 결정 하고 경기장 중심에서 반경 2.5의 원형 영역에 가까운 경향에 따라 결정합니다 . @Geobits의 답변에서 얻은 너트와 볼트 중 일부를 사용했습니다 (예 : 초록 포함)BattleBot클래스와 파싱 기술) 감사합니다! 지금까지 게시 한 다른 봇과 마찬가지로 잘 지내지 만 아마도 지금까지 가지고있는 것을 수정 / 확장 할 것입니다. 코드는 다음과 같습니다. (다른 사람이 Java를 사용하는 경우 자유롭게 내 추상 / 헬퍼 클래스를 사용하십시오.)

( 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();
    }
}

용법:

javac EvilBot.java
java EvilBot <input>

노트:

  • 현재 지뢰는 사용되지 않고 피하고 있습니다. 지뢰를 사용하는 것이 내가 실행 한 몇 가지 테스트로 판단 할 때 (적어도 EvilBot의 경우)보다 더 해로운 것으로 보입니다.

  • 현재 EMP를 사용하고 있지 않습니다. 나는 적들과 맞추고 EMP를 발사 한 후 미사일을 발사하는 전략을 시도했지만, 거의 100 %의 승리를 거둘 수있는 몇 가지 대응 전략이 있기 때문에 그 길을 포기하기로 결정했습니다. 나중에 다른 방법으로 EMP를 사용하는 방법을 알아볼 수 있습니다.


평균적으로 EvilBot는 Straight Shooter 5-0과 Dodging Turret 2-0을 이깁니다. Dodging Turret과 많은 관계가 있습니다.
intx13

@ intx13 그래, 나도 그것을 알아 차렸다. EvilBot과 Dodging Turret은 King 's Last Stand 와도 관련이 있습니다. 게임은 무한 루프로 줄어 듭니다.
arshajii

2
@arshajii 축하합니다.
Gareth

17

리프트

이 봇은 싸우는 봇에 따라 다른 행동을 취합니다. 상대방을 결정하기 위해 자신의 상태를 뒤집어 다른 봇에게 공급하여 자신이 무엇을하는지보고 실제 상황과 비교합니다. 그들이 '정확한'움직임의 임계 값에 도달하면, 다른 테스트는 중단됩니다.

그것이 싸움 봇 알고되면, 일반적으로 는 다음 턴에있을 곳이 해고 할 수 있도록, 알고 거기에 자신의 현재 위치를 대신.

물론 몇 가지 단점이 있습니다. 하나는 "무작위"활동이있는 봇이 잘 감지되지 않는다는 것입니다. 상대를 알 수없는 경우 King 's Last Stand 논리를 사용하여 균형을 맞 춥니 다.

그러나 봇이 순수하게 결정 론적이라면 봇이 누구인지 파악하는 데 아무런 문제 가 없습니다 . 그런 다음 각 상대방의 논리에 사례를 더 추가하여 상황에 쉽게 맞출 수 있습니다. 예를 들어, Last Stand와 싸우면 그를 모퉁이에 놓고 2x1 떨어져 서서 직접 움직이거나 발사 할 수 없으며 미사일을 벽 뒤에서 발사하여 스플래시로 죽입니다.

다른 사람들과 마찬가지로 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"};
}

와우 ... 특정 봇에 반응하는 봇을 얻는 데 얼마나 오래 걸리는지 궁금했습니다! 아주 늦게 출품작이 있으면 어떻게 되나요?
lochok

글쎄, 나는 그들이 들어올 때 더 많은 봇을 추가 할 계획입니다. 너무 늦게 커스터마이징 할 수있는 커플이 있으면 기본값이 여전히 잘 작동합니다.
Geobits

1
Hah, 나는 또한 어떤 종류의 봇과 싸우고 있는지를 알아내는 봇을 만들고 있습니다! 이제 추가로 업데이트하여 다른 봇을 식별하는 봇을 식별 할 수 있습니다! 또는 아마도 몇 가지 움직임을 속여서 당신을 속일 수도 있습니다! 무 하하!
Tom Verelst

1
@TomVerelst 이미 쉽게이 일을 방해하는 몇 가지 방법을 생각했습니다, 그래서되지 않습니다 너무 새로운 봇 내려 받아보고 놀랐. 즉, 현재 필드 에있는 봇에 대해 매우 훌륭하게 수행 됩니다. 마지막 로컬 테스트 실행에서 8/8 경기에서 승리했습니다. 때로는 DodgingTurret과 관련이 있지만, 그 패턴을 지속적으로 이길 수있는 싸움 패턴을 찾을 수 없으므로 두 승리를 거부하기 위해 묶는 것이 더 쉽습니다.
Geobits

그것이 스스로 재생된다면 어떨까요?
PyRulez

10

ReadyAimShoot

R의

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")

이 봇은 대상과 동일한 행 또는 열에 자신을 배치하려고 시도합니다. 대상과 정렬되면 EMP를 발사 한 후 다음 차례에 대상을 향해 미사일을 발사 한 다음 총알을 발사합니다. 또한 주변 광산을 알고 피해야하지만 총알과 미사일은 완전히 잊어 버리고 있습니다. 수명이 이미 1 인 경우 EMP를 건너 뜁니다.
EMP가 언제 트리거되는지 추적하기 위해 파일 끝에 주석을 추가하여 소스 코드를 수정합니다 ( #p_fired2처음에는 수정 #p_fired1한 다음 지 웁니다). 이 방법으로 EMP를 트리거하는 시점을 추적하는 것이 너무 경계 적이 지 않기를 바랍니다.

커맨드 라인은이어야 Rscript ReadyAimShoot.R하고, 예제에서와 같이 적어도 UNIX 시스템에서는 물론 Windows에서도 인수 가 있어야합니다 (실제로 다른 봇에 대해 테스트 할 때 확인합니다).

편집 : R 버전은 입력을 구문 분석하는 데 문제가있는 것 같으므로 여기에 동일한 봇의 파이썬 버전이 있습니다. 다른 R 프로그래머가 게시물을보고이 봇의 문제점을 발견하면 자유롭게 디버깅하십시오!

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)

아, 당신은 내가 생각했던 것과 같은 기술을 생각해 냈습니다 (주석에서 Einacio에게 언급했습니다). 나는 이것이 현재의 선두 주자가 될 것이라고 생각합니다. :-) 직장에서 집에 돌아올 때 시험해 볼게요.
Gareth

1
디스크에 쓰는 것에 대한 질문 끝에 섹션을 추가했습니다. 또한 첫 번째 테스트 실행을 수행했습니다. 결과는 질문의 끝 부분에 있습니다. 나는 이것을 상당히 정기적으로 시도하고 할 것입니다.
Gareth

이 봇이 이제 득점자와 함께 작동한다는 것을 의미한다고 생각합니다. 큰!
plannapus

것 같습니다. 그것은 쉽게 지뢰 광산과 RandomBot을 이겼지 만 EvadeBot과 DodingTurret에서 구타를했습니다.
Gareth

나는 그렇게 놀랐습니다 : 목표로 삼는 데 시간이 걸리기 때문에 (적대자와 매우 가까워지지 않으려 고 함) 나는 다저스와 잃을 것이라고 생각했습니다. 그래도 여전히 좋은 결과!
plannapus

8

왕의 마지막 대

내 확장 BattleBot은 EMP-blasters와 싸우도록 설계되었습니다. EMP를 사용하는 유일한 현명한 방법 (IMO)은 상대방과 같은 축에있는 동안 EMP를 발사 한 다음 붙어있는 상대방을 향해 미사일 / 무기를 쏘는 것입니다. 그래서 나는 축에서 벗어납니다 :)

만약 당신이 체스 게임을 왕과 왕비에 대항하여 왕에게 내려 가게된다면, 당신은 혼자 여왕이 검사 할 수 없다는 것을 알고 있습니다 . 당신은 왕을 참여시켜야합니다. 그렇지 않은 경우 고독한 왕의 전략은 쉽습니다. 이동성을 극대화하기 위해 축을 벗어나 중심을 향하도록 노력하십시오. 막히면 교착 상태에 빠지십시오.

물론, 여기에 교착 상태를 강요하는 좋은 방법은 없으므로 여왕이 어떤 수준의 능력을 발휘하고 있다면 결국 측면이나 구석에 붙어 있습니다. 이 봇이 그런 상황에 처해 있다면 쏴 버립니다. 상대방이 EMP를한다고 가정하면, 이것은 1 턴 데미지 이점을 제공하므로, 킹의 마지막 스탠드는 이미 생명력이 낮지 않으면 괜찮습니다.

아, 그리고 이미 발사 축에서 떨어져 있고 발사체로부터 안전하다면, 그것은 적의 일반적인 방향으로 쏘는 것입니다.

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;
    }   
}

실행을 컴파일하려면 다음을 사용하여 폴더에 BattleBot.java넣고 다음을 실행하십시오.

javac LastStand.java
java LastStand <arena-argument>

8

회 피봇

이 봇은 생존을 우선시합니다. 들어오는 충돌을 감지하면 해당 지점에서 충돌 을 확인하여 안전한 지점으로 이동합니다 . 주변의 "안전한"지점이 없으면 그대로두고 다음 단계로갑니다.

충돌이없는 경우 (또는 충돌의 경우 안전한 지점) 공격 검사를 수행합니다. 상대가 8 축으로 정렬되면 80 %의 시간을 발사합니다. 정렬되지 않으면 가장 가까운 제목에서 시간의 50 %를 발생시킵니다. 거리에 따라 무기를 선택합니다. 가까이 있으면 지뢰 또는 총알 (정확한 거리와 상대 건강에 따라 다름), 멀리서 미사일이 발사됩니다.

발사하지 않기로 결정한 경우 무작위로 걸어 (안전 지점을 다시 확인)합니다.

위의 방법 중 어느 것도 해결되지 않으면 다음 차례까지 그대로 앉아 있습니다.

EMP를 사용하지 않으며에 대해 ReadyAimShoot불평하는 것에 대해 나쁜 생각을 가지고 있지만 어떻게 진행되는지 볼 수 있습니다.


코드는 두 조각으로되어 있습니다. 하나 이상의 봇을 만들 수 있으므로 추상 BattleBot클래스를 만들었습니다 . 경기장 읽기, 충돌 확인, 제목 관리 등과 같은 도우미 기능이 포함되어 있습니다. 디버깅 중에 진행 상황을 추적하는 데 도움이되는 로그 기능도 있습니다. 인 경우 debug==false실제 출력 만 인쇄합니다. 누구나 사용 / 연장을 원한다면 자유롭게 느끼십시오. 그것은 아니다 코드,하지만 상용구를 작성 친다.

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;            
        }
    }   
}

특정 봇은 EvadeBot입니다. 컴파일 / 실행하려면 다음을 사용하여 폴더에 BattleBot.java넣고 다음을 실행하십시오.

javac EvadeBot.java
java EvadeBot <arena-argument>

인수를 생략하거나 올바르게 구문 분석 할 수없는 경우 기본적으로 "0"출력으로 설정됩니다.

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;
    }
}

1
좋은. MineMineMine과 RandomBot 5-0을 모두이기십시오.
Gareth

@ 케바 No prob. 어쨌든 나는 그것을하려고했다. 나는 누군가를 도울 수 있는지 알아, 시원합니다. 그것은 할 수 있지만, 훨씬 더합니다. 꽤 뼈대이지만 기본 사항이 있습니다.
Geobits

@Gareth에서 버그를 수정했습니다 BattleBots.java. 다음 실행 전에 내 봇을 다시 컴파일 할 수 있습니까?
Geobits

@Geobits 알겠습니다.
Gareth

8

스파이럴 봇 리터 레이트 하스켈

문해력있는 하스켈에서는 주석이 기본값이므로이 전체 게시물이 프로그램입니다. 이 봇은 입력을 무시하고 주위에 나선형으로 미사일을 발사합니다. 그것은 파일에 상태를 저장합니다.

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

먼저 미사일 행동을 나열합니다.

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

다음으로 IO 모나드로 바로갑니다. "spiral.txt"가 없으면 "0"을 씁니다. 디렉토리도 확인합니다.

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

그리고 우리는 그것을 읽고 행동을 인쇄합니다.

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

그리고 마지막으로 파일에 지금 위치를 씁니다.

>   writeFile "spiral.txt" (show $ actPos + 1)

1
@Geobits 디스크 쓰기에 관한 질문 끝에 섹션을 추가했습니다. 또한 첫 번째 테스트 실행을 수행했습니다. 결과는 질문의 끝 부분에 있습니다. 나는 이것을 상당히 정기적으로 시도 할 것이다.
Gareth

파일 쓰기에 대한 규칙을 보도록 요청할 수 있습니까? state다른 비 상태 파일과의 우발적 인 충돌을 피하기 위해 작성된 파일이 서브 디렉토리에 있어야 합니다.
Gareth

또한 테스트 시스템에 Haskell이 아직 설치되지 않았기 때문에 첫 번째 테스트 실행에 봇을 포함시키지 않았습니다. 설치 되 자마자 봇이 포함 된 상태에서 다른 테스트를 실행합니다.
Gareth

새 버전에 가져 오기가 누락 된 것 같습니다. 나는군요 LiterateHaskell.lhs:13:5: Not in scope: 'createDirectoryIfMissing'그리고 LiterateHaskell.lhs:14:5: Not in scope: 내가 컴파일 할 때 setCurrentDirectory'`.
Gareth

1
아이러니, 내 봇은 마지막 시점이지만 가장 많은 표를 얻었습니다. 승리를위한 프로그래밍 프로그래밍!
PyRulez

7

닷지 터릿

파이썬 봇

또 다른 시도가 있습니다. ReadyAimShoot는 잠시 동안 수리점에 있습니다. :) 이번에는 Python을 사용하여 그 동안 다른 것을 시도 할 것이라고 생각했습니다.

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)

나는 sys.argv[1].splitlines()@Gareth에서 부끄러운 줄 을 훔 쳤지 만 적어도 이번에는 입력을 구문 분석하는 데 문제가 없음을 의미합니다.

이 봇은 한판 승부가 시작될 때 중앙에서 달린 다음 그곳에 머물러 상대 방향으로 미사일을 발사합니다. 또한 근처에있는 총알과 미사일을 피하려고 시도하지만 다시 발사하기 전에 중앙으로 돌아갑니다.


2
대문자 함수 이름이 마음에 들지 않습니다.
Keba

이것은 내 "스트레이트 슈터"를 평균 3-2 정도 친다.
intx13

7

스트레이트 슈터

이것은 테스트에 사용할 수있는 또 다른 간단한 봇입니다. 상대방에게 직접 시선이 있다면, 쏴도 무작위로 밟습니다.

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']))

7

네오 봇

커피 스크립트

믹스에 추가 할 또 다른 JavaScript 봇. 이것은 Node.js를 대상으로하며 CoffeeScript로 작성되었습니다. 이 아키텍처는 일반적인 bottiness를 처리하는 기본 클래스와 봇을위한 특수 파일이있는 Java 군중에서 비롯됩니다.

이 봇의 주요 전략은 발사체에 맞지 않는 것입니다. 즉각적인 위협이 아닌 경우 네오 봇은 촬영을 시작합니다.

기본 파일 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

그리고 neo-bot.coffee봇 코드.

# 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()

실행하기 전에 커피 파일을 자바 스크립트로 컴파일하는 것이 좋습니다. 꽤 빠릅니다. 기본적으로 당신은 이것을하고 싶습니다 :

> coffee -c *.coffee
> ./bb "java EvilBot" "node ./neo-bot.js"

7

캠퍼 봇

이 봇은 그가있는 곳에 머물러서 쏴 버립니다. 다른 무기는 봇에 해를 끼칠 수 있으므로 총알 만 구현했습니다. 제 끔찍한 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;
}

실제로 많은 승리를 기대하지는 않습니다.


1
사이트에 오신 것을 환영합니다!
Jonathan Van Matre

1
약간의 버그 수정 ... 최종 실행을 위해 다시 컴파일 할 수 있습니까? 감사합니다 :)
CommonGuy

5

아직 출품작이 없으므로 출품작을 내놓을 수 있습니다. 나는 당신에게 준다 :

나의 것! 나의 것! 나의 것!

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))

특히 영리한 일은하지 않습니다. 주변 사각형에 아무 것도 없으면 광산을 떨어 뜨립니다. 그렇지 않으면 안전한 주변 사각형 중 하나로 이동합니다. HuggyBot을 거의 이길 수 없습니다.

naff Python 코딩을 용서하십시오.


5

랜덤 봇

이 봇은 움직일 때마다 무작위로 행동합니다. EMP를 발사하지 않으며지도를 전혀 보지 않습니다. 절반 만 벽에 발사됩니다!

#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;
  }
}

아래와 같이 자체 테스트하십시오.

$ gcc random.c -o random
$ ./bb random

즉해야 int main맞죠?
arshajii

main을 void로 정의하면 gcc는 리턴 코드를 0으로 설정합니다
intx13

바보 gcc. void mainBS입니다.
tomsmeding

5

말썽

싸움에서 루비 표현. 반대쪽 벽에서 무작위로 할당 된 벽 발사 미사일을 위아래로 이동합니다. 상단과 하단에 약간의 결함이 있습니다.

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

5

자바 스크립트 핵심

나는 친절하고 당신에게 나의 핵심 JS 봇을 줄 것이라고 생각했습니다. 봇을 만드는 데 필요한 모든 기능을 갖추고 있으며 필요한 데이터를 기반으로 수행해야 할 작업이 있습니다. 아직 테스트 할 수 없으므로 아직 완료되지 않았습니다 (아레나 코드를 컴파일 할 수 없음).

자유롭게 사용하십시오. 믹스에서 JS 봇을 기대하고 있습니다.

할 것:

  • 무기 위치를 계산하는 기능 추가

    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 ", ""));
    

유의하시기 바랍니다 (이 윈도우에서만 작동) 여기에 몇 가지 다른 OS에 맞게 수정해야 할 수도있다. Rhino 버전은 여기 : http://pastebin.com/FHvmHCB8


공감 및 의견이 없습니까? 이것을 다운 보트 한 사람이 나에게 이유를 줄 수 있습니까? 내 코드에 실수가 있습니까?
Corwin

예, 다운 투표자는 여기에 그들의 이의를 설명해야합니다.
Gareth

4

센터 봇

자바 스크립트 봇

이 봇은 경기장의 중간에 들어가는 것을 목표로합니다. 그것이 얼마나 가까이 있는지에 따라 매 턴마다 목표물에 총알이나 미사일을 쏘기위한 것입니다. 적이 중간에 있다면, 막연한 방향으로 총알을 계속 발사합니다.

나는 그것이 잘되는 것을 기대하지는 않지만 테스트하는 것 이상이며 실제로 얼마나 잘 수행되고 있는지 관심이 있습니다.

    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);
}

.js 파일로 저장하고로 실행하십시오 node centrebot.js. Node.js와 함께 작동하지만 다른 프로그램에 맞게 수정해야 할 수도 있습니다. 죄송합니다.

내 테스트에서 :

  • 스크래치없이 ReadyAimShoot를 처리했습니다.
  • DodgingTurret에 대항하여 대부분 승리
  • Randombot의 운이 좋은 지뢰에서 약간의 흠집으로 모두 승리
  • 스트레이트 슈터를 9 번에서 9 번 쳤지 만, 한 번에 모두 이겼음에도 불구하고 한판 승부가 가까웠습니다.

최고의 자바 봇을 테스트하지 않았으며 너무 자신감이 없습니다 ...


테스트 컴퓨터에 SpiderMonkey를 설치 했으므로 putstr(...)대신에를 사용 stdo.writeLine(...)하고 있으며 입력은에서 온 것 scriptArgs[0]입니다. 그런 다음지도를 선으로 분할 \\n하기 \n위해 를 변경해야 했습니다 . 내가 그것을 실행하면 때문에 오류가 발생 FindFoe()하고 findCentre()정의되어 있지만 호출되지 않습니다.
Gareth

죄송합니다! 방금 오류를 발견했습니다! 함수가 있지만 실제로는 실행하지 않습니다! 나의 나쁜, 나는 그것을 바꿀 것이다. 감사!
Corwin

다른 오류를 발견했습니다. 모든 방향이 앞뒤입니다. 당신은이 어디든지 E당신은이 있어야 W하고 당신은이 어디든지 S당신은이 있어야합니다 N. 질문의 입력 예를 사용하면 프로그램의 출력이 SE오른쪽 하단에서 가능한 방향이 아님을 알 수 있습니다. 다음 테스트 실행을 위해 수정했습니다.
Gareth

니스, @Gareth에게 감사드립니다. 서둘러 작성 했으므로 실제로 많은 오류 테스트를하지 않았습니다 ... 지금 고치겠습니다.
Corwin

3

CunningPlanBot (Python 3.3)

이것은 실제 인터페이스에서 완전히 테스트되지 않았습니다 ... 적어도지도에서 올바르게 작동합니다!

파이썬 3.3 용으로 작성되었습니다.

그것이하는 일 :

1 단계 인 경우-벽 및 방향이 벽으로 이동하거나 지뢰로 이동하는 경우 무작위로 벽이 아닌 방향 또는 지뢰 방향으로 변경-현재 방향으로 이동-2 단계로 이동

2 단계 인 경우-적에게 가장 가까운 방향으로 총알을 쏴-3 단계로 이동

3 단계 인 경우-지뢰가없는 경우 지뢰를 떨어 뜨립니다-1 단계로 이동

여전히 미사일 발사 여부를 파악해야합니다. 또한 지뢰를 피하는 것이 효과가 있는지에 대한 단서가 없습니다. 내일 저녁에 더 많은 테스트가 필요합니다.

#!/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()

2
득점 프로그램에서 작동하도록하기 위해해야 ​​할 몇 가지 작업 : sys.argv[1].splitlines()명령 행에서 입력 을 가져 와서 line[x][y]다음 블록에서 사용 했습니다. end=""스코어러를 혼동하는 개행을 제거하기 위해 인쇄 명령에 추가되었습니다 . state디렉토리 state자체가 아닌 파일을 파일에 쓰도록 상태를 변경했습니다 .
Gareth

에크! 사과드립니다. 나중에 밤에 나는 아마 그것을 보냈을 것이다. 최대한 빨리 사양을 준수하겠습니다!
lochok

문제 없습니다. 테스트 점수를 확인할 때까지 테스트 점수 매기기에 내 수정 프로그램을 사용합니다.
Gareth

동일한 수정 사항을 적용했지만 'Py_Initialise : sys 표준 스트림을 초기화 할 수 없습니다'라는 메시지가 표시됩니다. 소스 버전이 동일한 지 확인할 수 있습니까?
lochok

1
내 소스 버전을 게시물의 수정 사항으로 추가했습니다 (가장 쉬운 방법으로 보임). 소스를 가져 오면 롤백하십시오.
Gareth

3

울트라 봇

각 주변 필드의 위험을 계산하는 Java 봇. 주변 필드가 현재 필드보다 덜 위험한 경우 봇은 그곳으로 이동합니다 (또는 다른 위험 필드). 덜 위험한 필드가 없으면 봇이 쏴집니다 (적 봇이 멀리 있으면 미사일, 적 봇이 가까이 있으면 총알). BattleBot에서 코드를 가져 왔습니다 (감사합니다!).

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));
    }
}

이 봇은 치기가 매우 어렵지만 적을 쏘는 데는 좋지 않습니다… 여전히 이전 CamperBot보다 더 나을 것으로 기대합니다.


방금 컴파일하려고 시도하고 많은 오류가 발생했습니다. imports 가 누락 된 것 같 습니까?
Gareth

개인 접근에 관한 많은 오류들 :UltraBot.java:...: x has private access in Point
Gareth

업, 수입에 대해 잊어 버렸습니다 ... 또한 내 컴퓨터에서 작동하는 경우에도 x / y 액세스를 수정했습니다 ...
CommonGuy

1
괜찮 감사. 지금 내 컴퓨터에서 작동하고 있습니다.
Gareth

2

닌자 파이

파이썬에서 마지막 순간 제출 (미정이지만 희망적으로 작동합니다). 아이디어는 사각 지대에 머무르면서 상대방을 향해 전진한다는 것입니다. 충분히 가까이 있으면 (3 셀 떨어진) 상대방의 대각선에 위치하여 미사일을 발사합니다.

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)

늦은 입장에 대해 죄송합니다 : 지난 주 대부분의 회의에 참석했습니다.
plannapus
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.