KOTH: TNT Run Challenge

25

Dies wurde von einem Minecraft-Minispiel inspiriert. Die Regeln sind ziemlich einfach: Sie rennen und springen herum und jeder Block, auf den Sie treten, verschwindet, sobald Sie darauf getreten sind. Das Ziel ist, der Letzte zu sein, der noch übrig ist.

Ihr Bot sollte ein vollständiges Programm sein. Es sollte Eingaben als Befehlszeilenargument akzeptieren. Die Eingabe wird eine Karte der "Welt" sein; Hier ist ein Beispiel:

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         

Die Legende lautet wie folgt:

x: solid block

 : empty air

@: your bot

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

Ihr Bot sollte Ihren Zug als Ganzzahlenpaar ausgeben. Beispiel: -1, 2Bewegt sich 1 Block nach links und 2 Blöcke nach unten (Koordinatenursprung befindet sich in der oberen linken Ecke).

Sie können bis zu vier Blocks von Ihrem aktuellen Standort in Manhattan entfernt sein. Wenn Sie versuchen, sich weiter zu bewegen, ist die Bewegung ungültig. Jede Bewegung, die Sie über die Kante hinaus bewegt, bringt Sie stattdessen an die Kante. Ungültige Züge werden ignoriert.

Sobald Sie auf einem Block landen, wird dieser entfernt. Wenn Sie in der nächsten Runde auf demselben Block bleiben, werden Sie fallen. Zwei Bots können im selben Zug auf demselben Block landen und beide überleben. In diesem Fall sehen beide Bots nur sich selbst und nicht den anderen Bot.

Wenn Sie Dateien für die Persistenz speichern müssen, tun Sie dies bitte in einem Ordner mit dem Namen Ihres Bot. Sie können möglicherweise nicht die persistenten Daten anderer Bots lesen, sofern vorhanden.

Der Match Controller ist unter https://paste.ee/p/Xf65d verfügbar .

Bitte verwenden Sie Sprachen, die auf einer Standard-Linux- oder OSX-Installation ausgeführt werden können.

Aktuelle Ergebnisse (100 Runden):

JumpBot                   31
LookBot                   27
ShyBot                    26
Slow Bot                  15
KnightBot                 2
Moat Builder              0
UpBot                     0
Random Bot                0
Skyler
quelle
Ähnlich, obwohl ein wesentlicher Unterschied darin besteht, dass Sie mehrere Blöcke "springen" können - Sie können also nicht einfach jemanden blockieren, der sieht, was Sie tun.
Skyler
Sie können nicht als Betrüger in der Sandbox schließen und ich glaube nicht, dass es ganz eins ist
Blue
1
Sind die Bewegungen gleichzeitig oder sequentiell? Handelt es sich bei der Eingabe wirklich um eine Newline-haltige Zeichenfolge als Befehlszeilenargument?
Feersum
1
Ich würde vorschlagen, den Bot einmal ohne eine Welt zur Initialisierung aufzurufen (Sie wissen nicht, ob Ihr als Datei gespeicherter Status aus der letzten Runde oder aus dieser Runde stammt)
bauen1
@feersum bewegt sich gleichzeitig; Die Eingabe ist in der Tat ein Newline-haltiges Befehlszeilenargument. Wenn Sie es stattdessen als stdin benötigen, lassen Sie es mich wissen, und ich könnte wahrscheinlich den Controller so modifizieren, dass er beides zulässt.
Skyler

Antworten:

9

Langsamer Bot (Python)

Er bewegt sich in einem Linienmuster und überprüft seine Züge, bevor er sie ausführt (auch Selbstmorde, wenn er der letzte Lebende ist, der lange Laufzeiten verhindert). Er hat 195/200 Battels in meinem Testturnier gewonnen.

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

Ich bin kein Python-Experte und es gibt wahrscheinlich 100 Möglichkeiten, es kürzer / besser zu machen

bauen1
quelle
1
Nur eine Sache: Wenn Sie sich mit einem anderen Bot auf dem gleichen Feld befinden und die letzten beiden sind, denken Sie, dass es der letzte Selbstmord ist.
Timtech
Wenn ich Beharrlichkeit einsetze, wartet er 5 Runden bis zum Selbstmord
bauen1
Großartig, das wollte ich vorschlagen. Übrigens eine ausgezeichnete Antwort.
Timtech
6

JumpBot (C)

Versuche in der nächsten Runde mit möglichst vielen Zügen zum Feld zu springen.

#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;
}
Optokopper
quelle
5

LookBot (C)

Einfacher Bot, der in der Leistung dem langsamen Bot ähnlich ist, außer dass dieser zufällige mögliche Züge macht. Planen Sie, dies für PredictBot zu verbessern.

#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);
}
Tomsmeding
quelle
5

Wassergrabenbauer (Python)

Wenn ich einen Wassergraben um mich herum grabe, kann mich niemand außerhalb davon verarschen.

... auch bekannt als "Malen Sie sich in einen Eckensimulator 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)
Taixzo
quelle
Das klappt eigentlich ganz gut, aber es verliert gegen Bot, die lange leben (deshalb wähle ich
übrigens
Vielleicht möchten Sie Ihre Einrückung in smallmove () korrigieren ... Mein Python isst das nicht :)
tomsmeding
5

Monte (Python)

Sorry, das Wortspiel musste nur gemacht werden.

Wie auch immer, dieser Bot führt eine Monte-Carlo-Baumsuche für alle möglichen Zugsets durch. Denken Sie an JumpBot, nur tiefer.

Zum Ausführen ist ein zusätzliches Befehlszeilenargument erforderlich (kann im Controller angegeben werden). Es steuert, nach wie viel Zeit der Bot suchen soll (in ms); Ich habe 750-1500 beim Testen verwendet.

Code:

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

Versuche

25 Runden:

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

100 Runden:

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

200 Runden:

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

Alle oben genannten Simulationen verwendeten die Suchzeit 750. Dieser Bot wäre wahrscheinlich mit einer längeren Suchzeit sogar noch besser (ich weiß nicht, wie hoch die zulässige Höchstzahl ist).

Verbesserungen

Dieser Bot muss noch verbessert werden in:

  1. Leistung: Zum Suchen wird die gesamte Zeit benötigt.
  2. Vorhersage: Es wird nicht für die Bewegungen anderer Bots verantwortlich sein.
  3. Balance: Ich bin nicht sicher, ob die UCT-Formel, mit der ich den zu untersuchenden Knoten ermittle, optimal ist.
Blau
quelle
4

ShyBot (Python)

Dieser Bot mag keine anderen Bots und wird versuchen, sich selbst fernzuhalten, wenn dies möglich ist. ShyBot achtet auch sehr genau darauf, wohin es geht. es wird nicht einmal auf andere Bots treten. ShyBot verliert jedoch immer noch häufig, was unsicher macht.

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))
Blau
quelle
4

KnightBot (Java)

Es funktioniert wie Schach und heißt wie Twitch ...

...

.........

............................Es tut uns leid...

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

Dies sind eindeutig nicht die optimalen Lösungen, aber ich hoffe, dass sie für Tests auf mittlerer Ebene nützlich sind.

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');
   }
}
Cheeseitup
quelle
Hallo und willkommen bei PPCG! Gute Antwort!
NoOneIsHere
2

Zufälliger Bot, UpBot

Zwei Start-Bots, gegen die man antreten kann:

Zufälliger Bot: Ein Beispiel-Bot, der sich zufällig bewegt.

import random

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

UpBot: Ein Beispiel-Bot, der sich nach oben bewegt.

print '0 -1'
Skyler
quelle
Ich habe 10 Testrunden für meine (jetzt gelöschte) Random Walker-Antwort durchgeführt, und komischerweise geht es UpBot sehr gut. Er hat 7 von 10 Runden.
user48538
UpBot macht es gut, weil er sich immer nur um einen Block bewegt, sodass er normalerweise länger braucht, um gegen eine Wand zu rennen, als Random Bot, um in ein Loch zu laufen.
Skyler
1
@ zyabin101: Du kannst es einfach ausführen, 'y' drücken, um ein komplettes Turnier zu spielen, und 10 für die Runden eingeben.
Skyler
1

StalkerBot (Python)

Kommt dem nächsten Bot so nah wie möglich. Zielt auf den (sinnlosen) automatischen Selbstmord von Slow Bot ab. (Wenn ich auf dem gleichen Feld bin und keine anderen Spieler da sind, wird es mich nicht sehen und wird Selbstmord begehen.)

#!/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()))
Solomon Ucko
quelle
1
Nur zu Ihrer Information, im Allgemeinen genehmigen wir keine Änderungen, die den Code ändern (wie die, die Sie bei einer anderen Antwort auf diese Frage vorgenommen haben). Ich stimmte dem zu, da es anscheinend nichts mit der Logik zu tun hatte, sondern es nur bereinigte, aber das wird bei den meisten Antworten nicht funktionieren. Das könnte man aber definitiv gebrauchen.
19.
@ Riker Verstanden. Es ist sinnvoll, die Logik nicht zu ändern, aber ich hatte Probleme, diesen Code zu lesen, und entschied mich, die Formatierung zu bereinigen.
Solomon Ucko
1
Kein Problem, aber denken Sie daran, dass Golfbearbeitungen und ähnliches bei zukünftigen Fragen wahrscheinlich abgelehnt werden. Ich bin damit einverstanden, dass der Code, den Sie bearbeitet haben, ein bisschen wackelig war.
19.
1
@Riker Nehmen Sie grundsätzlich keine Änderungen vor, die sich auf die Punktzahl auswirken könnten.
Solomon Ucko