BattleBots: การแข่งขัน


69

ผลลัพธ์อยู่ในการแข่งขันสิ้นสุดแล้ว
ผู้ชนะคือEvilBot ของ arshajiiพร้อมด้วย 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)

นี่เป็นความท้าทายที่เยี่ยม เป้าหมายคือการเขียนบอทที่จะเอาชนะบอทอื่น ๆ ได้มากกว่าบอทอื่น ๆ

เกม

บอททั้งหมดจะถูกหลุมต่อกัน 2 ครั้งในเวที 10x10 โดยมีภารกิจลดพลังงานของฝ่ายตรงข้ามลงจาก 10 เป็น 0 ก่อนที่พลังงานของมันจะลดลงเหลือ 0

แต่ละการแข่งขันจะประกอบด้วย 5 การแข่งขัน ผู้ชนะการแข่งขันเป็นผู้ชนะการแข่งขันมากที่สุด จำนวนทั้งหมดของการแข่งขันที่ชนะและการแข่งขันจะถูกเก็บไว้ในโปรแกรมควบคุมและจะถูกใช้เพื่อกำหนดผู้ชนะการแข่งขันโดยรวม ผู้ชนะจะได้รับเครื่องหมายสีเขียวขนาดใหญ่และการประจบสอพลอของฝูง

การแข่งขันแต่ละครั้งจะดำเนินการเป็นรอบ ที่จุดเริ่มต้นของแต่ละรอบสถานะปัจจุบันของเวทีจะมอบให้กับแต่ละบอทและบอทจะตอบกลับด้วยคำสั่งเพื่อกำหนดสิ่งที่มันต้องการจะทำต่อไป เมื่อได้รับคำสั่งจากทั้งสองโปรแกรมแล้วทั้งสองคำสั่งจะถูกดำเนินการในเวลาเดียวกันและระดับพลังงานของเวทีและบอทจะได้รับการอัพเดตเพื่อให้สอดคล้องกับสถานะใหม่ หากบอททั้งสองยังมีพลังงานเพียงพอที่จะดำเนินการต่อเกมจะเข้าสู่รอบต่อไป จะมีการ จำกัด 1,000 รอบต่อการแข่งขันเพื่อให้แน่ใจว่าไม่มีการแข่งขันจะดำเนินต่อไปตลอดไปและในกรณีที่ถึงขีด จำกัด นี้ผู้ชนะจะเป็นบอทที่มีพลังงานมากที่สุด หากบอททั้งสองมีพลังงานเท่ากันการแข่งขันนั้นเสมอกันและบอททั้งคู่จะไม่ได้รับคะแนนสำหรับการชนะ (มันจะเหมือนกับว่าพวกเขาแพ้ทั้งคู่)

อาวุธ

แต่ละบอทจะมีอาวุธจำนวนหนึ่ง:

  • กระสุนเจาะเกราะ การเดินทางครั้งละ 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

เนื่องจากอาจได้รับคำสั่งเพียงหนึ่งคำสั่งต่อรอบบอทสามารถย้ายหรือยิง / ปรับใช้อาวุธเท่านั้นไม่สามารถทำทั้งสองอย่างในเวลาเดียวกัน

ลำดับของคำสั่ง
การเคลื่อนไหวของบอทใด ๆ จะมาก่อนเสมอและการเคลื่อนไหวทั้งหมดจะพยายามสองครั้งเพื่ออธิบายบอทอื่นที่กำลังขวางทาง แต่เคลื่อนออกนอกเส้นทาง

ตัวอย่าง

  • Bot1 พยายามย้ายEแต่ Bot2 อยู่ในช่องนั้นแล้ว
  • โปรแกรมควบคุมย้ายไปยัง Bot2
  • Bot2 พยายามย้ายSและประสบความสำเร็จเพราะไม่มีอะไรขวางทาง
  • Bot1 ได้รับความพยายามครั้งที่สองในการย้าย Eในครั้งนี้จะประสบความสำเร็จและย้าย Bot1

เมื่อบอททำการเคลื่อนไหวใด ๆ ที่พวกเขาต้องการอาวุธจะถูกยิงและขีปนาวุธทั้งหมด (ใหม่และก่อนหน้านี้ยิง) จะย้ายจำนวนสี่เหลี่ยมที่กำหนดไว้ล่วงหน้า

สนามกีฬา

ที่จุดเริ่มต้นของแต่ละรอบ bot จะได้รับสถานะการเล่นปัจจุบันเป็นอาร์กิวเมนต์บรรทัดคำสั่งของโปรแกรมเท่านั้น:

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ได้เขียนกรุณารุ่นที่มีประสิทธิภาพมากขึ้นของโปรแกรมควบคุมที่มีการแก้ไขข้อบกพร่องบางอย่างที่คุณสามารถหาได้ที่นี่

ข้อเสนอแนะสำหรับการปรับปรุงหรือแก้ไขข้อบกพร่องในโปรแกรมควบคุมยินดีต้อนรับ

ทดสอบบ็อต

ไม่มีบอททดสอบใด ๆ ที่จะรวมอยู่ในการให้คะแนน พวกมันแค่เพื่อการทดสอบ

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

พยายามที่จะได้รับขวาถัดจากฝ่ายตรงข้าม ความเสี่ยงต่อการทุ่นระเบิดเนื่องจากไม่ได้มองหาพวกเขา ทำให้การยิงขีปนาวุธเป็นกลยุทธ์ที่มีประสิทธิภาพน้อยกว่าสำหรับคู่ต่อสู้เมื่อบรรลุเป้าหมาย

ผลที่ได้

วิ่งให้คะแนนสุดท้ายจะทำหลังจากที่23:59 ใน 24 มีนาคม 2014 ฉันจะทำการทดสอบวิ่งเป็นประจำเพื่อให้ผู้เข้าร่วมสามารถเห็นว่าบอทของพวกเขาซ้อนกันอย่างไรกับการต่อต้านในปัจจุบัน

รายการ

รายการควรมีแหล่งที่มาของบอทของคุณและอาร์กิวเมนต์บรรทัดคำสั่งที่ฉันจะต้องใช้เพื่อเรียกใช้ คุณสามารถโพสต์ข้อความต่าง ๆ ได้มากเท่าที่คุณต้องการ แต่คำตอบแต่ละคำตอบควรมีบอทเดียวเท่านั้น

สิ่งสำคัญ

ดูเหมือนว่าบางรายการต้องการเขียนไปยังดิสก์เพื่อรักษาสถานะระหว่างการทำงาน นี่เป็นกฎใหม่เกี่ยวกับการเขียนลงดิสก์

  • คุณสามารถแก้ไขแหล่งที่มาของบอทของคุณเอง การดัดแปลงบอทอื่นเป็นการโกงและจะส่งผลให้บอทที่ถูกละเมิดถูกตัดสิทธิ์
  • คุณสามารถเขียนไปยังไฟล์ที่สร้างขึ้นเพื่อวัตถุประสงค์ในการจัดเก็บของรัฐ ไฟล์นี้จะต้องเก็บไว้ในไดเรกทอรีย่อยของไดเรกทอรีที่บอทของคุณอยู่ stateไดเรกทอรีย่อยจะถูกตั้งชื่อ การเขียนไปยังส่วนอื่น ๆ ของระบบไฟล์ (นอกเหนือจากแหล่งที่มาของคุณเอง) ไม่ได้รับอนุญาต

1
ขออภัยฉันไม่ได้จับสิ่งนี้ใน Sandbox: อาวุธทุกอย่างไม่มีที่สิ้นสุดหรือไม่?
Jonathan Van Matre

2
@ intx13 บางทีบอทที่สอดคล้องกับบ็อต 1 และอันที่ตรงกับบ็อต 2 ไม่ควรสุ่มทุกการแข่งขัน แต่เลือกสุ่มในการแข่งขันครั้งแรกเท่านั้นและสลับที่จุดเริ่มต้นของการแข่งขันต่อไปนี้
arshajii

2
ฉันคิดว่าฉันพบข้อบกพร่องในรหัสของ @ intx13 เมื่อทั้งคู่บอทยิง EMP ในเวลาเดียวกันฉันคิดว่าทั้งคู่ควรสูญเสียพลังงาน ฉันยังไม่ได้รันรหัสของเขา แต่ดูแล้วนี่ไม่ได้เป็นอย่างนั้น ดูบรรทัด 295-304 github.com/gazrogers/CodegolfBattlebotsScorer/blob/master/ …
Thomas Eding

2
ข้อผิดพลาดที่อาจเกิดขึ้นอีก ดูเหมือนว่าพลังงานของบอทนั้นจะต่ำกว่าศูนย์ได้ ไม่เป็นไร แต่ถ้า Bot1 มี -1 พลังงานและ Bot2 มี 0 พลังงานไม่ควรทำคะแนนชนะ
Thomas Eding

2
ขอบคุณสำหรับทัวร์นาเมนต์นี้ @Gareth มันเป็นความท้าทายที่ดีและเป็นแรงบันดาลใจให้ฉันสำรวจพื้นที่ใหม่ ๆ ในการเขียนโปรแกรม จะท้าทายเพื่อนของฉันบางคนที่ฉันคิดว่า :) ขอบคุณผู้เข้าร่วมทุกคนเกมที่ดี!
Corwin

คำตอบ:


14

EvilBot

บอทที่พยายามทำตัวชั่วร้ายที่สุด

นี่คือสิ่งที่ฉันได้รับ: บ็อต Java ที่พยายามเข้าใกล้คู่ต่อสู้ด้วยแถบวงกลมรัศมี 2.5 รอบจุดศูนย์กลางของเวทีที่เป็นไปได้แล้วทำดาเมจเท่าที่จะทำได้ รูปแบบการเคลื่อนไหวของมันนั้นขึ้นอยู่กับการกำหนดค่า "อันตราย" ให้กับแต่ละสี่เหลี่ยมที่อยู่ใกล้เคียงและตัดสินใจที่จะย้ายตามค่าเหล่านี้และขึ้นอยู่กับแนวโน้มที่จะใกล้เคียงกับรัศมีวงกลม 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

Rifter

บอทนี้ใช้การกระทำที่แตกต่างกันไปตามบอทที่กำลังต่อสู้ ในการกำหนดคู่ต่อสู้มันจะพลิกสถานะของตัวเองและป้อนมันเข้าไปในบอทอื่นเพื่อดูว่าพวกเขาจะทำอะไรและเปรียบเทียบกับสิ่งที่พวกเขาทำจริง ๆ เมื่อพวกเขาไปถึงขีด จำกัด ของการเคลื่อนไหว 'ถูกต้อง' มันจะหยุดการทดสอบอื่น ๆ

เมื่อรู้ว่าบอทกำลังต่อสู้อะไรมันมักรู้ว่ามันจะอยู่ที่ไหนในเทิร์นถัดไปดังนั้นมันจึงสามารถยิงได้ที่นั่นแทนที่จะอยู่ในตำแหน่งปัจจุบัน

แน่นอนว่ามีข้อเสียอยู่บ้าง หนึ่งคือบอตที่มีกิจกรรม "สุ่ม" ไม่ได้รับการตรวจพบ สิ่งนี้มีความสมดุลโดยใช้ลอจิกล่าสุดของ King เมื่อไม่ทราบคู่ต่อสู้

อย่างไรก็ตามถ้าบอทถูกกำหนดอย่างหมดจดสิ่งนี้จะไม่มีปัญหาในการหาว่ามันคือใคร จากนั้นจะสามารถปรับให้เข้ากับสถานการณ์ได้ง่ายขึ้นโดยการเพิ่มเคสเข้าไปในตรรกะของคู่ต่อสู้แต่ละราย ตัวอย่างเช่นการต่อสู้ 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
ฮ่าฮ่าฉันกำลังทำงานกับบอทที่พยายามระบุว่าบอทชนิดใดที่กำลังต่อสู้กับ! ตอนนี้ฉันสามารถปรับปรุงเพิ่มเติมและทำให้มันระบุบอทที่ระบุบอทอื่น ๆ ! หรืออาจหลอกคุณโดยแกล้งทำท่าทาง! Muahaha!
Tom Verelst

1
@TomVerelst ฉันคิดแล้วไม่กี่วิธีที่จะสามารถขัดขวางคนนี้ดังนั้นฉันจะไม่เกินไปแปลกใจที่เห็นบอใหม่เอามันลง อย่างที่บอกไปแล้วว่ามันดีมาก ๆ กับบ็อตที่อยู่ในสนามซึ่งเป็นสิ่งที่ฉันต้องการ มันชนะการแข่งขัน 8/8 ในการทดสอบครั้งสุดท้ายในท้องถิ่นของฉัน บางครั้งมันก็ผูกกับ DodgingTurret แต่ฉันไม่สามารถหารูปแบบการต่อสู้ที่จะเอาชนะมันได้อย่างสม่ำเสมอดังนั้นมันง่ายกว่าที่จะปล่อยให้มันผูกติดกับการปฏิเสธทั้งคู่
Geobits

ถ้ามันเล่นเอง
PyRulez

10

ReadyAimShoot

R Bot

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

บอทนี้พยายามวางตัวเองในแถวหรือคอลัมน์เดียวกันกับเป้าหมายเมื่อมันสอดคล้องกับเป้าหมายมันจะยิง 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

ดูเหมือนว่าจะ มันสามารถเอาชนะ mineminemine และ RandomBot ได้อย่างง่ายดาย แต่เอามาจาก EvadeBot และ DodingTurret ของคุณ
Gareth

ฉันไม่แปลกใจที่: เพราะมันใช้เวลาในการเล็ง (ไม่พยายามใกล้เคียงกับปฏิปักษ์) ฉันคิดว่ามันจะแพ้กับดอดเจอร์ส แม้ว่าจะยังค่อนข้างดีอยู่ก็ตาม!
plannapus

8

King's Last Stand

ส่วนขยายของฉันBattleBotนี้ถูกออกแบบมาเพื่อต่อสู้กับ EMP-blaster วิธีเดียวที่สมเหตุสมผล (IMO) เพื่อใช้ EMP คือการยิงมันในขณะที่คุณอยู่บนแกนเดียวกับคู่ต่อสู้จากนั้นยิงขีปนาวุธ / อาวุธไปยังคู่ต่อสู้ที่ติดอยู่ ดังนั้นฉันจะอยู่นอกแกน :)

หากคุณเคยมีเกมหมากรุกลงไปหาราชากับราชา + ราชินีคุณรู้ว่าราชินีคนเดียวไม่สามารถรุกฆาตคุณจะต้องเข้าร่วมราชา ถ้าคุณทำไม่ได้กลยุทธ์ของกษัตริย์ผู้โดดเดี่ยวนั้นเป็นเรื่องง่าย: พยายามอยู่นอกแกนและมุ่งไปที่ศูนย์กลางเพื่อเพิ่มความคล่องตัว หากคุณติดขัดไปจนมุมจนเกินไป

แน่นอนว่าไม่มีวิธีที่ดีในการบังคับทางตันที่นี่ดังนั้นในที่สุดคุณก็ติดอยู่ที่ด้านข้างหรือมุมถ้าราชินีกำลังเล่นในระดับความสามารถใด ๆ หากบอทนี้เคยอยู่ในสถานการณ์เช่นนั้นมันจะยิง สมมติว่าฝ่ายตรงข้ามกำลังจะเข้าสู่ EMP สิ่งนี้จะสร้างความได้เปรียบในการทำลายในครั้งเดียวดังนั้นขาตั้งสุดท้ายของกษัตริย์ควรจะไม่เป็นไรเว้นแต่เขาจะมีชีวิตอยู่ในระดับต่ำ

โอ้และถ้ามันอยู่นอกแนวแกนและปลอดภัยจากขีปนาวุธมันก็จะยิงระยะไกลในทิศทางทั่วไปของศัตรู

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

หากต้องการคอมไพล์ run ให้วางในโฟลเดอร์ที่มีBattleBot.javaและรัน:

javac LastStand.java
java LastStand <arena-argument>

8

EvadeBot

บอทนี้ให้ความสำคัญกับการมีชีวิตอยู่ หากตรวจพบการชนที่เข้ามาก็พยายามที่จะย้ายไปยังจุดที่ปลอดภัยโดยการตรวจสอบว่าจุดสำหรับชน หากไม่มีจุด "ปลอดภัย" อยู่รอบ ๆ จุดนั้นจะยังคงอยู่และไปยังขั้นตอนถัดไป

หากไม่มีการชนกัน (หรือจุดที่ปลอดภัยในกรณีที่เกิดการชน) จะทำการตรวจสอบการโจมตี หากฝ่ายตรงข้ามอยู่ในแนว 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

@Keba ไม่มีปัญหา ฉันจะทำมันต่อไป; ฉันคิดว่ามันช่วยให้ใครบางคนออกมาเท่ห์ มันอาจจะดีขึ้นมากแม้ว่า มันค่อนข้างเปลือยเปล่า แต่มีพื้นฐานที่ฉันเดา
Geobits

@Gareth BattleBots.javaฉันคงข้อผิดพลาดใน คุณช่วยคอมไพล์บ็อตของฉันอีกครั้งก่อนจะรันครั้งต่อไปได้หรือไม่?
Geobits

@Geobits โอเคจะทำ
Gareth

8

บอท Spiral Haskell

ในคลังความรู้ความคิดเห็นเป็นค่าเริ่มต้นดังนั้นโพสต์ทั้งหมดนี้จึงเป็นโปรแกรม บอทนี้จะยิงขีปนาวุธเป็นวง ๆ รอบ ๆ โดยไม่สนใจอินพุต มันเก็บสถานะในไฟล์ (ซึ่งหวังว่าจะไม่ถูกโพสต์โดยนักการตลาด)

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

ครั้งแรกที่เราแสดงรายการการกระทำของขีปนาวุธ

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

ต่อไปเราจะเข้าสู่ IO monad หากไม่มี "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

DodgingTurret

ธ ธ ธ

นี่คือความพยายามอื่น เนื่องจาก 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

นีโอบอท

CoffeeScript

บอท JavaScript ตัวอื่นที่จะเพิ่มลงในมิกซ์ เป้าหมายนี้เป็นเป้าหมายเดียวของ Node.js และเขียนเป็น CoffeeScript สถาปัตยกรรมดังต่อไปนี้มาจากฝูงชน Java ที่มีคลาสพื้นฐานการจัดการความไม่แน่นอนและไฟล์อื่นที่มีความเชี่ยวชาญสำหรับบอทที่อยู่ในมือ

กลยุทธ์หลักของบอทนี้คือไม่โดนโดนขีปนาวุธของคุณ หากคุณไม่ได้เป็น neo-bot ขู่ว่าจะเริ่มยิง

ไฟล์ฐาน 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

CamperBot

บอทนี้อยู่ที่ที่เขาอยู่และยิง ฉันใช้กระสุนเพียงนัดเดียวเพราะอาวุธชนิดอื่นอาจทำอันตรายต่อบอท โปรดยกโทษให้ฉันทักษะ 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

gcc จะตั้งค่ารหัสส่งคืนเป็น 0 หากคุณกำหนด main เป็นโมฆะ
intx13

โง่ gcc void mainคือ BS
tomsmeding

5

ปัญหาและ Strafe

การเป็นตัวแทนทับทิมในการต่อสู้ เลื่อนขึ้นและลงเพื่อยิงขีปนาวุธบนผนังที่กำหนดแบบสุ่มที่ผนังฝั่งตรงข้าม มีข้อผิดพลาดเล็กน้อยที่ด้านบนและด้านล่าง

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

แกน JavaScript

ฉันคิดว่าฉันเป็นคนใจดีและให้บอทหลักของฉันแก่คุณ มันมีฟังก์ชั่นทั้งหมดที่จำเป็นสำหรับการทำบอทสิ่งที่คุณต้องมีก็คือการกระทำบางอย่างที่ต้องทำตามข้อมูลที่ให้นี้ ยังไม่เสร็จเนื่องจากฉันไม่สามารถทดสอบได้ (ไม่สามารถรวบรวมรหัสเวทีได้)

รู้สึกอิสระที่จะใช้สิ่งนี้ฉันรอคอยที่จะเห็นบางบอท 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 ", ""));
    

โปรดทราบว่าบางสิ่งที่นี่อาจจะต้องมีการปรับเปลี่ยนสำหรับระบบปฏิบัติการอื่น ๆ (ใช้ได้กับ Windows เท่านั้น) รุ่นแรดที่นี่: http://pastebin.com/FHvmHCB8


ลงคะแนนและไม่มีความคิดเห็น? ใครก็ตามที่ลงคะแนนในข้อนี้โปรดให้เหตุผลฉัน ในรหัสของฉันมีข้อผิดพลาดหรือไม่?
Corwin

ใช่ผู้ลงคะแนนเสียงต้องอธิบายคำคัดค้านของพวกเขาที่นี่
Gareth

4

ศูนย์-Bot

บอท JavaScript

บอทนี้มีจุดมุ่งหมายที่จะเข้าสู่กลางเวทีก่อนที่จะยิงกระสุนหรือขีปนาวุธที่เป้าหมายของมันในแต่ละรอบขึ้นอยู่กับว่ามันอยู่ใกล้แค่ไหน หากศัตรูอยู่ตรงกลางมันจะยิงกระสุนต่อไปในทิศทางที่คลุมเครือ

ฉันไม่คาดหวังว่ามันจะทำได้ดีมาก แต่เป็นการทดสอบมากกว่าและฉันสนใจที่จะดูว่ามันใช้งานได้ดีเพียงใด

    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 แต่คุณอาจต้องแก้ไขมันสำหรับโปรแกรมอื่นขออภัยด้วย!

ในการทดสอบของฉัน:

  • Thrashed ReadyAimShoot โดยไม่มีรอยขีดข่วน
  • ชนะมากที่สุดกับ DodgingTurret
  • รับรางวัลทั้งหมดด้วยรอยขีดข่วนเล็ก ๆ น้อย ๆ จากทุ่นระเบิดโชคดีจาก Randombot
  • เอาชนะนักแม่นปืนตรง 9 ครั้งจาก 9 ครั้ง แต่การแข่งขันแต่ละนัดนั้นอยู่ใกล้แม้ว่าฉันจะชนะทุกคนก็ตาม

ยังไม่ได้ทดสอบบ็อต Java ชั้นนำใด ๆ และฉันก็ไม่มั่นใจเช่นกัน ...


ผมได้ติดตั้งแมงมุมบนเครื่องทดสอบเพื่อให้ฉันใช้putstr(...)แทนของคุณและใส่มาจากstdo.writeLine(...) scriptArgs[0]มีการกระทำที่ฉันต้องการที่จะเปลี่ยน\\nไป\nในการแยกแผนที่ในสาย เมื่อฉันเรียกใช้ฉันได้รับข้อผิดพลาดเพราะFindFoe()และfindCentre()มีการกำหนด แต่ไม่ได้เรียก
Gareth

อ๊ะ! เพิ่งพบข้อผิดพลาด! ฉันมีฟังก์ชั่น แต่ไม่ได้ใช้จริง! ไม่ดีฉันจะเปลี่ยนมัน ขอบคุณ!
Corwin

ฉันพบข้อผิดพลาดอื่น - ทิศทางทั้งหมดกลับไปข้างหน้า เมื่อใดก็ตามที่คุณมีEคุณควรจะมีWและทุกที่ที่คุณมีคุณควรจะมีS Nหากคุณใช้ตัวอย่างอินพุตจากคำถามคุณจะเห็นว่าเอาต์พุตจากโปรแกรมSEนั้นไม่ใช่ทิศทางที่เป็นไปได้จากมุมขวาล่าง ฉันแก้ไขให้ถูกต้องเพื่อการทดสอบครั้งต่อไป
Gareth

สวัสดีขอบคุณ @Gareth ฉันรีบเขียนดังนั้นฉันจึงไม่ได้ทำการทดสอบข้อผิดพลาดมากนัก ... จะแก้ไขได้ทันที
Corwin

3

CunningPlanBot (Python 3.3)

นี่ไม่ได้ทดสอบอย่างสมบูรณ์ภายใต้อินเทอร์เฟซจริง ... มันทำงานได้อย่างถูกต้องกับแผนที่อย่างน้อย!

มันเขียนสำหรับ Python 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

UltraBot

บอท 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 ก่อนหน้าของฉัน


เพียงแค่พยายามรวบรวมมันและโยนข้อผิดพลาดมากมาย ดูเหมือนว่ามันหายไปบางส่วนimport?
Gareth

ข้อผิดพลาดมากมายเกี่ยวกับการเข้าถึงแบบส่วนตัวเช่นกัน:UltraBot.java:...: x has private access in Point
Gareth

อัพลืมเกี่ยวกับการนำเข้า ... ยังแก้ไข x / y-access แม้ว่ามันจะทำงานบนเครื่องของฉัน ...
CommonGuy

1
โอเคขอบคุณ. ตอนนี้มันทำงานบนเครื่องของฉันแล้ว
Gareth

2

NinjaPy

การส่งในนาทีสุดท้ายในไพ ธ อน (ยังไม่ทดลอง แต่หวังว่าจะใช้ได้) แนวคิดก็คือมันจะเคลื่อนไปหาคู่ต่อสู้ในขณะที่อยู่ในจุดบอด เมื่อมันอยู่ใกล้พอ (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.