KOTH : TNT 런 챌린지


25

이것은 Minecraft 미니 게임에서 영감을 얻었습니다. 규칙은 매우 간단합니다. 뛰어 다니고 뛰어 다니며 밟으면 모든 블록이 사라집니다. 목표는 마지막 남은 것입니다.

봇은 완전한 프로그램이어야합니다. 입력을 명령 행 인수로 승인해야합니다. 입력은 "세계"의지도가 될 것입니다. 다음은 예입니다.

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxx xxxxxxxxxxxxxxxxxxxxxxxxxxx
xxx xxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxx x xxxxxxxxxxxxx@xxxxxxxxxxx
xxxxxx1xxxxxxxxxxxxx xxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx xxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx xxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx xxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx xxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx xxxxxxxxxxx
xxxxxxxxxx           xxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxx xxxxxxxxxxxx
xxxxxxxxxxxxxxxxx x x xxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx xxxxxxxxxxx
xxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxx xxx xx3xxxxxxxxxx
xxxxxxxxxxxxxxxxxxx xxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxx  x
xxxxxxxxxxxxxxxxxxxxxxxxxxx   xx
xxxxxxxxxxxxxxxxxxxxxxxxx      2
xxxxxxxxxxxxxxxxxxxxxxx         

범례는 다음과 같습니다.

x: solid block

 : empty air

@: your bot

1,2,3,4,5,6,7,8,9,0: other bots

봇은 이동을 정수 쌍으로 출력해야합니다. 예 : -1, 21 블록을 왼쪽으로 이동하고 2 블록을 아래로 이동합니다 (좌표 원점이 왼쪽 상단에 있음).

현재 위치에서 맨해튼 거리까지 최대 4 개의 블록을 이동할 수 있습니다. 그 이상으로 이동하려고하면 이동이 유효하지 않습니다. 가장자리를 넘어 이동하는 모든 움직임은 대신 가장자리에 당신을 배치합니다. 잘못된 움직임은 무시됩니다.

블록에 착륙하면 제거됩니다. 다음 턴에 같은 블록에 머무르면 넘어집니다. 두 봇은 같은 턴에 같은 블록에 착륙하여 둘 다 생존 할 수 있습니다. 이 경우 두 봇은 다른 봇이 아닌 자신 만 볼 수 있습니다.

지속성을 위해 파일을 저장해야하는 경우 봇 이름의 폴더에 저장하십시오. 다른 봇의 영구 데이터가 있으면 읽을 수 없습니다.

일치 컨트롤러는 https://paste.ee/p/Xf65d 에서 사용할 수 있습니다 .

표준 Linux 또는 OSX 설치에서 실행할 수있는 언어를 사용하십시오.

현재 결과 (100 라운드) :

JumpBot                   31
LookBot                   27
ShyBot                    26
Slow Bot                  15
KnightBot                 2
Moat Builder              0
UpBot                     0
Random Bot                0

이와 유사하지만 여기서 중요한 차이점은 여러 블록을 "점프"할 수 있다는 것입니다. 따라서 다른 사람이 자신의 작업을보고 있으면 단순히 누군가를 차단할 수 없습니다.
Skyler

당신은 샌드 박스에서 속임수로 닫을 수 없으며 나는 그것이 하나라고 생각하지 않습니다
Blue

1
움직임이 동시에 또는 순차적입니까? 입력이 실제로 줄 바꾸기를 포함하는 문자열입니까?
feersum

1
초기화를 위해 월드없이 한 번 봇을 호출하는 것이 좋습니다 (파일로 저장된 상태가 마지막 라운드인지 또는이 라운드인지 알 수 없음)
bauen1

@feersum 이동은 동시에 이루어집니다. 입력은 실제로 개행을 포함하는 명령 행 인수입니다. 대신 stdin으로 필요하면 알려 주시면 아마도 컨트롤러를 수정하여 둘 중 하나를 허용 할 수 있습니다.
Skyler

답변:


9

느린 봇 (파이썬)

그는 선 패턴으로 움직여 움직이기 전에 움직임을 확인합니다 (오랫동안 런타임을 막기 위해 마지막으로 살았을 때 자살) 테스트 토너먼트에서 195/200 Battels을 얻었습니다.

import sys
import re


class vec2(object):
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def __add__(self, other):
        return vec2(self.x + other.x, self.y + other.y)

    def __sub__(self, other):
        return vec2(self.x - other.x, self.y - other.y)

    def __iadd__(self, other):
        return self + other

    def __isub__(self, other):
        return self - other

    def __neg__(self):
        return vec2(-self.x, -self.y)


def xy_to_i(vec=vec2(0, 0)):
    vec -= vec2(1, 1)
    vec.y += (vec.x - vec.x % 32) / 32
    return vec.x + vec.y * 33


def i_to_xy(i=0):
    vec = vec2(0, 0)
    vec.x = i % 33
    vec.y = (i - vec.x) / 32 + 1
    vec.x += 1
    return vec


class World(object):
    def __init__(self, map=''):
        self.map = map

    def getPlayerPosition(self):
        return i_to_xy(re.search('@', self.map).start())

    def getNumOtherBots(self):
        return len(re.findall('([0123456789])', ' ' + self.map + ' '))

    def get_tile(self, vec=vec2(0, 0)):
        i = xy_to_i(vec)
        return self.map[i:i + 1]


world = World(sys.argv[1])
pos = world.getPlayerPosition()


def check_moveV(vecd=vec2(0, 0)):
    try:
        vecn = pos + vecd

        if vecn.x > 32 or vecn.x < 1 or vecn.y > 32 or vecn.y < 1 \
            or abs(vecd.x) + abs(vecd.y) > 4:
            return False

        # Note: this will also avoid positions other bots are on (will disappear in the next step).

        return world.get_tile(vecn) == 'x'
    except:
        raise
        return False


def check_move(x=0, y=0):
    return check_moveV(vec2(x, y))


def run():
    if world.getNumOtherBots() == 0:
        return '0 0'  # Suicide if we are the only one left.

    # this creates the "line" pattern

    if check_move(0, -1):
        return '0 -1'

    if check_move(0, 1):
        return '0 1'

    if check_move(1, 0):
        return '1 0'

    if check_move(1, -1):
        return '1 -1'

    # If we get here, we are desperate and need to find a safe place to jump.

    for dx in range(-2, 2):
        for dy in range(-2, 2):
            if check_move(dx, dy):
                return '%i %i' % (dx, dy)

    # If we can't find a place to jump in close range, try long range.

    for dx in range(-4, 4):
        for dy in range(-4, 4):
            if check_move(dx, dy):
                return '%i %i' % (dx, dy)

    # If we get here, we are dead no matter what; accept our fate.

    return '0 0'


print(run())

나는 파이썬 전문가가 아니며 아마도 짧거나 더 나은 100 가지 방법이 있습니다.


1
한 가지만, 다른 봇과 같은 공간에 있고 마지막 두 사람이라면 마지막 것이 자살이라고 생각할 것입니다.
Timtech

내가 지속성을 구현할 때, 그는 자살까지 5 라운드 기다립니다
bauen1

좋아요, 그것이 제가 제안한 것입니다. 그건 그렇고 훌륭한 답변입니다.
Timtech

6

점프 봇 (C)

다음 라운드에서 가장 많은 움직임으로 필드로 점프하십시오.

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

typedef struct map {
     char *raw_map;
     int size;
     int lines;
     char *pos;
} *MAP;

typedef struct cdata {
     int result;
     MAP m;
     int x;
     int y;
} *CDATA;

typedef struct mdata {
     int x;
     int y;
     int moves;
     int bx;
     int by;
     MAP m;
} *MDATA;

int numberOfMoves(MAP, int, int);
char getAt(MAP, int, int);

int abs(int x)
{
    return x < 0 ? x*-1 : x;
}

void count(void *data, int x, int y)
{
    CDATA d = (CDATA)data;
    char c = getAt(d->m, d->x + x, d->y + y);
    if(c != 'x') return;
    d->result++;
}

void choose(void *data, int x, int y)
{
    MDATA m = (MDATA)data;
    char c = getAt(m->m, m->x + x, m->y + y);
    if(c != 'x') return;
    int moves = numberOfMoves(m->m, m->x+x, m->y+y);
    if(moves > m->moves || (!m->bx && !m->by)) {
        m->moves = moves;
        m->bx = x;
        m->by = y;
    }
}

MAP parse_input(char *input)
{
    MAP m = malloc(sizeof *m);
    if(!m) {
        fprintf(stderr, "failed to alloc map\n");
        return NULL;
    }

    m->size=0;
    m->lines=1;
    m->pos=0;

    char *temp;
    for(temp = input;*temp;temp++) {
        switch(*temp) {
            case '\n': m->lines++; break;
            default: break;
        }
    }
    m->size = (temp + 1) - (input + m->lines);
    m->raw_map = malloc(m->size);
    if(!m->raw_map) {
        fprintf(stderr, "failed to alloc raw_map\n");
        return NULL;
    }

    int index = 0;
    for(temp = input; *temp; temp++) {
        if(*temp == '@') m->pos = m->raw_map + index;
        if(*temp != '\n') m->raw_map[index++] = *temp;
    }

    return m;
}

char getAt(MAP m, int x, int y)
{
    return m->raw_map[x + y*(m->size / m->lines)];
}

void posToXY(MAP m, int *x, int *y)
{
    int index = m->pos - m->raw_map;
    int length = m->size / m->lines;
    *x = index % length;
    *y = index / length;
}

typedef void (*DOFUNC)(void *, int, int);
void processMoves(MAP m, int x, int y, DOFUNC proc, void *data)
{
    int length = m->size / m->lines;    
    int left = x>=4 ? 4 : x;
    int right = x + 4 <= length ? 4 : length - (x + 1);
    int up = y >= 4 ? 4 : y;
    int down = y + 4 <= m->lines ? 4 : m->lines - (y + 1);

    for(int i=-left; i<=right; i++) {
        for(int j=-up; j<=down; j++) {
            if((abs(i) + abs(j) <= 4) && (i || j)) (*proc)(data, i, j);
        }
    }
}

int numberOfMoves(MAP m, int x, int y)
{
    struct cdata d;
    d.result = 0;
    d.x = x;
    d.y = y;
    d.m = m;
    processMoves(m, x, y, &count, &d);
    return d.result;
}

void getMove(MAP m, int *x, int *y)
{
    struct mdata d;
    posToXY(m, &d.x, &d.y);
    d.moves = 0;
    d.bx = 0;
    d.by = 0;
    d.m = m;
    processMoves(m, d.x, d.y, &choose, &d);
    *x = d.bx;
    *y = d.by;
}

int main(int argc, char *argv[])
{
    if(argc != 2) {
        fprintf(stderr, "bad number of arguments %d\n", argc);
        return -1;
    }

    MAP m = parse_input(argv[1]);
    int x=0, y=0;
    getMove(m, &x, &y);
    printf("%d %d\n", x, y);
    return 0;
}

5

룩봇 (C)

Slow Bot과 비슷한 성능의 간단한 봇은 무작위로 움직일 수 있습니다. 이것을 PredictBot로 개선 할 계획을 세우십시오.

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <sys/time.h>

#define WORLDSZ (32)
#define WORLDSZ_2 (WORLDSZ*WORLDSZ)

int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}

struct Position{
    int x,y;
};
typedef struct Position Position;

struct World{
    Position me;
    double enemymap[WORLDSZ][WORLDSZ]; //chance of enemy present
    bool open[WORLDSZ][WORLDSZ];
};
typedef struct World World;

void world_read(World *world,const char *arg){
    int x,y,i=0;
    for(y=0;y<WORLDSZ;y++,i++){
        for(x=0;x<WORLDSZ;x++,i++){
            if(arg[i]=='@'){world->me.x=x; world->me.y=y;}
            world->enemymap[y][x]=arg[i]>='0'&&arg[i]<='9';
            world->open[y][x]=arg[i]=='x';
        }
    }
}

//returns relative position
Position world_calcmove(World *world){
    const int mex=world->me.x,mey=world->me.y;
    int dx,dy;
    Position poss[40];
    int nposs=0;
    for(dy=max(-mey,-4);dy<=min(WORLDSZ-1-mey,4);dy++){
        const int absdy=abs(dy);
        for(dx=max(-mex,absdy-4);dx<=min(WORLDSZ-1-mex,4-absdy);dx++){
            if(!world->open[mey+dy][mex+dx])continue;
            poss[nposs].x=dx;
            poss[nposs++].y=dy;
        }
    }
    if(nposs==0){
        poss[0].x=poss[0].y=0;
        return poss[0];
    }
    return poss[rand()%nposs];
}

int main(int argc,char **argv){
    if(argc!=2){
        fprintf(stderr,"Call with world!\n");
        return 1;
    }
    struct timeval tv;
    gettimeofday(&tv,NULL);
    srand(tv.tv_sec*1000000ULL+tv.tv_usec);

    World world;
    world_read(&world,argv[1]);
    Position move=world_calcmove(&world);
    printf("%d %d\n",move.x,move.y);
}

5

해자 건축업자 (Python)

내가 내 주위에 해자를 파면, 그 밖에 아무도 나를 망치지 못합니다.

"코너 시뮬레이터 2016에 자신을 그리십시오"라고도합니다.

import numpy
import sys
import math
import os

if not os.path.exists('./moatbuilder'):
    os.mkdir('./moatbuilder')

raw_field = sys.argv[1]
field = numpy.array([numpy.array(list(i)) for i in raw_field.splitlines()])
field_size = len(field)
x, y = raw_field.replace('\n','').index('@')%field_size, int(raw_field.replace('\n','').index('@')/field_size)
# If there are no holes, it's the first round - reset persistence
if raw_field.count(' ')==0:
    open('./moatbuilder/persistent','w').write('')

def bigmove(target):
    if x < target[0]:
        return min(4, target[0] - x), 0
    elif x > target[0]:
        return max(-4, target[0] - x), 0
    elif y < target[1]:
        return 0, min(4, target[1] - y)
    else:
        return 0, max(-4, target[1] - y)

def smallmove(target):
        if x < target[0]:
        try:
            return min(max(1, list(field[y][x:x+4]).index('x')), target[0] - x), 0
        except:
            return 0, 0
        elif x > target[0]:
        try:
            return max(min(-1, 0-list(reversed(field[y][x-4:x])).index('x')), target[0] - x), 0
        except:
            return 0, 0
        elif y < target[1]:  
        try:
                    return 0, min(max(1, list(field[:,x][y:y+4]).index('x')), target[1] - y)
        except:
            return 0, 0
        else:
        try:
            return 0, max(min(-1, 0-list(reversed(field[:,x][y-4:y])).index('x')), target[1] - y)
        except:
            return 0, 0


try:
    mode = int(open('./moatbuilder/persistent').read())
except:
    mode = 1

# Modes:
# 1 - go to the center
# 2 - go to an outside edge
# 3 - dig moat
if mode==1:
    dx, dy = bigmove((int(field_size/2), int(field_size/2)))
    if dx==0 and dy==0:
        open('./moatbuilder/persistent', 'w').write('2')
        mode = 2
if mode==2:
    dx, dy = bigmove((int(field_size-1), int(field_size/2)))
    if dx==0 and dy==0:
        dy = 1
        open('./moatbuilder/persistent', 'w').write('3')
        mode = 3
elif mode==3:
    direction = max(field_size-x, field_size-y)%2
    if direction == 1:
        if x > y:
            dx, dy = smallmove((y, y))
        else:
            dx, dy = smallmove((x, field_size - 1))
        if dx==0 and dy==0:
            dx = 1
    else:
        if y > x:
            dx, dy = smallmove((x, x))
        else:
            dx, dy = smallmove((field_size - 1, y))
        if dx==0 and dy==0:
            dy = 1

print "%i %i" % (dx, dy)

이것은 실제로 매우 좋게 동작하지만, 봇에 잃을 것이다 오랫동안 라이브 (내가 BTW 라인 패턴을 선택하는 이유 먹으 렴)
bauen1

smallmove ()에서 들여 쓰기를 수정하고 싶을 수도 있습니다 ... 내 파이썬은 이것을 먹지 않습니다 :)
tomsmeding

5

몬테 (파이썬)

미안, 그 말장난은 방금 만들어야 했어.

어쨌든이 봇은 가능한 모든 이동 세트에서 Monte Carlo Tree Search 를 수행하여 작동 합니다. 좀 더 깊이있는 JumpBot을 생각해보십시오.

실행하려면 추가 명령 행 인수가 필요합니다 (컨트롤러에서 지정할 수 있음). 봇이 검색해야하는 시간 (ms)을 제어합니다. 테스트에 750-1500을 사용했습니다.

암호:

import sys
import math
import copy
#from profilestats import profile
pmap = sys.argv[2].split("\n")
pmap = [list(r) for r in pmap]

#find a player
#@profile
def find(tmap,bot):
   r,c=-1,-1
   for row in range(len(tmap)):
      for col in range(len(tmap[row])):
         if tmap[row][col]==bot:
            r,c=row,col
   return r,c

mer,mec=find(pmap,'@')
bots=[(mer,mec)]

#find all the other players
for b in range(10):
   r,c=find(pmap,str(b))
   if r != -1:
      bots.append((r,c))

#getter function, treats oob as spaces
def get(tmap,r,c):
   if r<0 or r>=len(tmap) or c<0 or c>=len(tmap[r]):
      return ' '
   return tmap[r][c]

#returns manhattan distance between 2 positions  
def dist(r1,c1,r2,c2):
   return abs(r1-r2)+abs(c1-c2)

#gets all possible moves from a map
#@profile 
def moves(tmap,ther=-1,thec=-1):
   if ther==-1: ther,thec = find(tmap,'@')
   pos=[]
   for r in range(-4,5):
      for c in range(-4,5):
         if abs(r)+abs(c)<=4 and get(tmap,ther+r,thec+c)=='x':
            pos.append((r,c))
   return pos


ttlmoves = 40
#monte-carlo tree node
class MCNode:
   def __init__(self):
      self.wins=0
      self.simu=0
      self.chld=[]
      self.cmap=[[]]
      self.prnt=None
      self.r=-1
      self.c=-1
   def add(self, cnode):
      self.chld.append(cnode)
      cnode.prnt = self
   #used to balance exploitation and exploration
   #@profile
   def param(self,cin):
      return self.chld[cin].wins/self.chld[cin].simu\
             + 1.414 * math.sqrt( math.log(self.simu) / \
             self.chld[cin].simu )
   #finds the child with the highest param
   #@profile
   def best(self):
      vals = [self.param(x) for x in range(len(self.chld))]
      binx = 0
      bval = vals[0]
      for x in range(len(vals)):
         if vals[x]>bval:
            binx=x
            bval=vals[x]
      return self.chld[binx]


#update all the parents 
#@profile   
def backprog(leaf):
   par = leaf.prnt
   if not (par is None):
      par.wins+=leaf.wins
      par.simu+=leaf.simu
      backprog(par)

#expand all the moves from a position
#@profile
def expand(rootn):
   ther,thec = rootn.r,rootn.c
   for r,c in moves(rootn.cmap,rootn.r,rootn.c):
      nmap = copy.deepcopy(rootn.cmap)
      nmap[ther+r][thec+c] = '@'
      nmap[ther][thec]=' '
      nnode = MCNode()
      nm = moves(nmap,ther+r,ther+c)
      nnode.wins = len(nm)
      nnode.simu = ttlmoves
      nnode.r=ther+r
      nnode.c=thec+c
      nnode.cmap = nmap
      rootn.add(nnode)
      backprog(nnode)

root = MCNode()
m = moves(pmap,mer,mec)
root.wins = len(m)
root.simu = ttlmoves
root.cmap=copy.deepcopy(pmap)
root.r=mer
root.c=mec
expand(root)

#simulate a bunch of outcomes
import time
curt  = lambda: int(round(time.time() * 1000))
strt = curt()
ttme = int(sys.argv[1])
while curt()-strt < ttme:
   tnode=root
   while tnode.chld:
      tnode=tnode.best()
   expand(tnode)

#choose the most explored one
bnode = max(root.chld,key=lambda n:n.simu)

#output
print("{} {}".format((bnode.c-mec),(bnode.r-mer)))

시험판

25 라운드 :

MonteBot            14
JumpBot             6
ShyBot              5
LookBot             1
KnightBot           0
SlowBot             0

100 라운드 :

JumpBot             38
MonteBot            36
ShyBot              15
LookBot             14
SlowBot             2
KnightBot           0

200 라운드 :

MonteBot            87
JumpBot             64
LookBot             33
ShyBot              21
SlowBot             5
KnightBot           0

위의 모든 시뮬레이션은 검색 시간 750을 사용했습니다.이 봇은 아마도 더 긴 검색 시간으로 더 나을 것입니다 (최대 허용치가 무엇인지 모르겠습니다).

개량

이 봇은 여전히 ​​다음 사항을 개선해야합니다.

  1. 성능 : 검색하려면 전체 시간이 필요합니다.
  2. 예측 : 다른 봇의 움직임을 설명하지 않습니다.
  3. 균형 : 탐색해야하는 노드를 계산하기 위해 사용중인 UCT 수식이 최적인지 확실하지 않습니다.

4

사이 봇 (파이썬)

이 봇은 실제로 다른 봇을 좋아하지 않으며 가능한 경우 스스로를 멀리하려고 노력할 것입니다. ShyBot은 또한 그것이 어디로 향하는 지 신중하게 생각합니다. 다른 봇도 밟지 않습니다. 그러나 ShyBot은 여전히 ​​느슨해져 불안전합니다.

import sys
map = sys.argv[1]
map = map.split("\n")
map = [list(r) for r in map]

def find(map,bot):
   r,c=-1,-1
   for row in range(len(map)):
      for col in range(len(map[row])):
         if map[row][col]==bot:
            r,c=row,col
   return r,c


mer,mec=find(map,'@')
bots=[(mer,mec)]

for b in range(10):
   r,c=find(map,str(b))
   if r != -1:
      bots.append((r,c))

avg=[0,0]

for b in bots:
   avg[0]+=b[0]
   avg[1]+=b[1]

avg[0] = avg[0]/len(bots)
avg[1] = avg[1]/len(bots)

def get(map,r,c):
   if r<0 or r>=len(map) or c<0 or c>=len(map[r]):
      return ' '
   return map[r][c]

def dist(r1,c1,r2,c2):
   return abs(r1-r2)+abs(c1-c2)

pos=[]
for r in range(-4,5):
   for c in range(-4,5):
      if abs(r)+abs(c)<=4 and get(map,mer+r,mec+c)=='x':
         pos.append((r,c))

if len(pos)==0:
   bestr,bestc=0,0
else:
   bestr,bestc=pos[0]

for r,c in pos:
   if dist(mer+r,mec+c,avg[0],avg[1])>dist(mer+bestr,mec+bestc,avg[0],avg[1]):
      bestr,bestc=r,c

print(str(bestc)+" "+str(bestr))

4

KnightBot (자바)

그것은 체스처럼 작동하며 Twitch와 같은 이름을 갖습니다 ...

...

.........

............................죄송합니다...

public class KnightBot{
   private static String[] map;
   private static int myx;
   private static int myy;
   public static void main(String[] args){
      map=args[0].split("\n");
      for(int y=0;y<map.length;y++){
         if(map[y].indexOf("@")!=-1){
            myy = y;
            myx = map[y].indexOf("@");
            break;
         }
      }
      System.out.println(move((int)(Math.random()*4),4));
   }
   public static String move(int dir,int tries){
      if(tries==0)return "0 0";
      int x=dir<2?1:-1;
      int y=dir%2==0?2:-2;
      if((myx+x<0||myx+x>=map[0].length()||myy+y<0||myy+y>=map.length)||map[y+myy].charAt(myx+x)!='x'){
         x=dir<2?2:-2;
         y=dir%2==0?1:-1;
      }
      if((myx+x<0||myx+x>=map[0].length()||myy+y<0||myy+y>=map.length)||map[y+myy].charAt(myx+x)!='x')
         return move(++dir>3?0:dir,tries-1);
      return x+" "+y;
   }
}

SwirlyBot (자바)

이것들은 최적의 솔루션은 아니지만 분명히 중간 수준의 테스트에 유용하기를 바랍니다.

public class SwirlyBot{
   private static String[] map;
   private static int myx;
   private static int myy;
   public static void main(String[] args){
      map=args[0].split("\n");
      for(int y=0;y<map.length;y++){
         if(map[y].indexOf("@")!=-1){
            myy = y;
            myx = map[y].indexOf("@");
            break;
         }
      }
      System.out.println(move(0));
   }
   public static String move(int dir){
      switch(dir){
         case 0:
            if(!safe(0,1)){
               if(safe(1,1)){
                  return "1 1";//Down-Right
               }else{
                  if(safe(1,0)){
                     return "1 0";//Right
                  }
               }
            }
            break;
         case 1:
            if(!safe(1,0)){
               if(safe(1,-1)){
                  return "1 -1";//Up-Right
               }else{
                  if(safe(0,-1)){
                     return "0 -1";//Up
                  }
               }
            }
            break;
         case 2:
            if(!safe(0,-1)){
               if(safe(-1,-1)){
                  return "-1 -1";//Up-Left
               }else{
                  if(safe(-1,0)){
                     return "-1 0";//Left
                  }
               }
            }
            break;
         case 3:
            if(!safe(-1,0)){
               if(safe(-1,1)){
                  return "-1 1";//Down-Left
               }else{
                  if(safe(0,1)){
                     return "0 1";//Down
                  }
               }
            }
            break;
         case 4:
            if(safe(0,-1))return "0 -1";
            break;
         case 5:
            if(!safe(0,2)){
               if(safe(1,2)){
                  return "1 2";//Down-Right
               }else{
                  if(safe(2,2)){
                     return "2 2";
                  }else{
                     if(safe(2,1)){
                        return "2 1";
                     }else{
                        if(safe(2,0)){
                           return "2 0";//Right
                        }
                     }
                  }
               }
            }
            break;
         case 6:
            if(!safe(2,0)){
               if(safe(2,-1)){
                  return "2 -1";//Up-Right
               }else{
                  if(safe(2,-2)){
                     return "2 -2";
                  }else{
                     if(safe(1,-2)){
                        return "1 -2";
                     }else{
                        if(safe(0,-2)){
                           return "0 -2";//Up
                        }
                     }
                  }
               }
            }
            break;
         case 7:
            if(!safe(0,-2)){
               if(safe(-1,-2)){
                  return "-1 -2";//Up-Left
               }else{
                  if(safe(-2,-2)){
                     return "-2 -2";
                  }else{
                     if(safe(-2,-1)){
                        return "-2 -1";
                     }else{
                        if(safe(-2,0)){
                           return "-2 0";//Left
                        }
                     }
                  }
               }
            }
            break;
         case 8:
            if(!safe(-2,0)){
               if(safe(-2,1)){
                  return "-2 1";//Down-Left
               }else{
                  if(safe(-2,2)){
                     return "-2 2";
                  }else{
                     if(safe(-1,2)){
                        return "-1 2";
                     }else{
                        if(safe(0,2)){
                           return "0 2";//Down
                        }
                     }
                  }
               }
            }
            break;
      }
      if(dir<8)return move(dir+1);
      return "0 -1";
   }
   public static boolean safe(int x, int y){
      return !((myx+x<0||myx+x>=map[0].length()||myy+y<0||myy+y>=map.length)||map[y+myy].charAt(myx+x)!='x');
   }
}

안녕하세요, PPCG에 오신 것을 환영합니다! 좋은 답변입니다!
NoOneIsHere 여기

2

랜덤 봇, 업봇

경쟁을위한 2 개의 스타트 봇 :

랜덤 봇 : 무작위로 움직이는 예제 봇.

import random

x = random.randint(-4, 4)
y = random.randint(max(-4, -4 + abs(x)), min(4, 4 - abs(x)))
print x, y

UpBot : 위로 움직이는 예제 봇.

print '0 -1'

나는 (지금 삭제 된) Random Walker 답변에 대해 10 회 테스트 라운드를 실행했으며 유감스럽게도 UpBot은 매우 잘하고 있습니다. 그는 10 라운드 중 7 개를 얻었다.
user48538



UpBot은 한 번에 하나의 블록 만 움직이기 때문에 잘 작동하므로 랜덤 봇보다 구멍을 뚫을 때보 다 벽에 걸리는 시간이 더 오래 걸립니다.
Skyler

1
@ zyabin101 : 아시다시피, 전체 토너먼트를하기 위해 'y'를 누르고 라운드에 10을 입력하면됩니다.
Skyler

1

스토커 봇 (Python)

가장 가까운 봇에 최대한 가까이 접근합니다. 슬로우 봇 (무의미한) 자동 자살을 목표로합니다. (내가 같은 광장에 있고 다른 플레이어가 없다면, 나를 보지 않고 자살 할 것입니다.)

#!/usr/bin/python3
from math import inf
from sys import argv

class Vector:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    def __sub__(self, other):
        return Vector(self.x - other.x, self.y - other.y)

    def __neg__(self):
        return Vector(-self.x, -self.y)

    def __abs__(self):
        return self.x ** 2 + self.y ** 2  # Technically the square of the magnitude, but we only need it for comparison.

    def __iter__(self):
        yield self.x
        yield self.y

def get_location(grid, target='@'):
    for i, line in enumerate(grid):
        for j, char in enumerate(line):
            if char == target:
                return Vector(i, j)

def main(grid):
    my_location = get_location()

    min_distance = inf
    min_distance_direction = None

    for i in range(10):
        enemy_location = get_location(str(i))

        if enemy_location is not None:
            direction = enemy_location - my_location
            distance = abs(direction)

            if distance < current_min:
                min_distance = distance
                min_distance_direction = direction

            if distance == 1:
                break

    if min_distance_direction is not None:
        return min_distance_direction

    for d in range(1, 5):
        for x in range(-d, d):
            for y in (d - abs(x), abs(x) - d):
                if grid[x][y] == ' ':
                    return x, y

    return 0, 0

if __name__ == '__main__':
    print(*main(argv[1].splitlines()))

1
참고로, 일반적으로 코드를 변경하는 수정 사항 (이 질문에 대한 다른 답변에서 수행 한 수정 사항)은 승인하지 않습니다. 나는 논리 나 다른 것에 닿지 않은 것처럼 보였지만 그것을 정리 한 것처럼 보였지만 대부분의 대답을하지는 않을 것이라고 승인했습니다. 그래도 확실히 사용할 수 있습니다.
Rɪᴋᴇʀ

@Riker는 이해했다. 논리를 변경하지 않는 것이 합리적이지만 해당 코드를 읽는 데 문제가있어서 서식을 정리하기로 결정했습니다.
Solomon Ucko

1
문제는 없지만 앞으로 진행될 다른 질문에 대해서는 골프 편집 및 이와 유사한 내용이 거부 될 수 있습니다. 나는 당신이 편집 한 코드가 다소 기발한 것에 동의합니다.
Rɪᴋᴇʀ

1
@Riker 기본적으로 점수에 영향을 줄 수있는 편집은하지 마십시오.
Solomon Ucko
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.