Печерні рейнджери - вивчення пітьми


9

Ваш приятель-геолог ледь не збив двері у вашому кабінеті, коли він увірвався, широко схвильований, і попросив вас зайти з ним на сайт, який він щойно знайшов. По дорозі він пояснює, що вважає, що він буквально просто вразив золото. Єдина проблема полягає в тому, що він закопаний глибоко під землею в печері з дуже нестійким дахом. Це занадто небезпечно розбиратися, тому він хоче, щоб ви запрограмували одного з його печерних роботів, щоб зібрати якомога більше золота, перш ніж він витягне його назад. Він також згадує, що пробував печеру і знайшов дику природу, яка може бути шкідливою для роботів, а також, що він кинув там обладнання, яке може бути корисним. Кожен робот оснащений двома руками і датчиком. Коли ви приїдете на місце події, він каже вам, що планує набрати більше кодерів,

Тепер, аж до азотно-зернистого. Датчики передають інформацію вашій програмі як символи ASCII. Ось перелік того, що означає кожен персонаж, та описи всього, що може виникнути в печері.

Code    Name/Description

Y       Your bot
        You do things

@       Other bots
        They do other things

-       Ground
        This doesn't do things

C       Centipede
        These will bite you and leave a poison effect
        The bite will cost 1 health
        The poison effect will last for 3 turns, costing 2 health each turn

B       Bats
        If bats end up in the same space you are, your bot runs in a random direction during its turn rather than what you told it to do

L       Lion (because reasons)
        Lions deal heavy damage, 10 health, each time they attack

F       Food
        Eating this will give you 5 health
        Can only be used once

W       Water
        Drinking this will cure poison effects early
        Can only be used once

R       Revealer
        This will increase the range of your visibility to an 11x11 grid
        The extra range will only be 75% correct, but the original range won't be effected

K       Knife
        You do twice as much damage to other bots if you have a knife

G       Gold
        The whole reason you're doing this in the first place

N       Nurse Nina
        She mend you good
        Restores your health by 10 while you occupy the same space as her

}       Boulder
        You can't walk over boulders, and neither can anything else

P       Pit
        If you fall in a pit, you will be stuck for 3 turns

Розмір каверни зростає на основі кількості ботів. Він починається як 30x30, і він отримує додаткові 10x10 для кожного бота. Тож 2 боти будуть досліджувати печеру розміром 50x50.

Боти починаються з 20 здоров'я, але вони не мають максимального обмеження на здоров'я.

Вхід:

Ви отримаєте вхід через STDIN у такому форматі:

20,5,10,1,0,True,False    <-health, number gold pieces, number of turns your bot has lasted, number of until the poison wears off, number of turns until you are no longer stuck in a pit, if you have a revealer, if you have a knife
-----
-G}--
--Y-L
-C---
---B-

Перший рядок містить інформацію про вашого бота, а решта - сітка, яку може бачити ваш бот. Якщо ваш бот прилягає до однієї з 4-х стін печери, ви отримаєте сітку, яка виглядає приблизно так (у випадку, якщо ви знаходитесь аж до Заходу):

---
}--
Y--
---
---

Печера не обертається, а також не бачить ваше бачення. Стіни печери не позначені, єдиний показник, який ваш бот отримує, що він наближається до стіни, - це зменшення його виду. З Revealer ви можете отримати щось подібне:

--------C--
LW--------B
---K-N-----
--------BR-
-F---------
--B--Y---@N
-W@---F----
------K-F--
----@-}----
R@---G}--}-
--------G-R

Вихід:

Ви отримуєте два ходи за оборот, які виводите у такому форматі:

MNNANW    <- Moves are groups of 3 characters representing the action and the direction

Можливі дії:

M    Move - Move your bot in the specified direction
A    Attack - Attack the square in the specified direction
H    Hold - Do nothing

Можливі вказівки:

NN - North (up)
NE - Northeast (up-right)
EE - East (right)
SE - Southeast (down-right)
SS - South
SW - Southwest
WW - West
NW - Northwest

Рухи застосовуються зліва направо.

Виходить:

Досягає прогресу наступним чином:

  1. Ефекти отрути застосовуються до будь-якого гравця, який отруївся

  2. Неботи рухаються та атакують

    2а. Леви, сороконіжки і кажани рухаються випадковим чином

    2б. Леви та сороконіжки атакують усе, що безпосередньо прилягає до нього (у тому числі по діагоналі)

    2в. Ефект кажана буде застосований до бота, лише якщо він знаходиться на тому ж просторі, що і кажан

    2d. Медсестра Ніна залишиться на місці протягом 3 витків, а потім перескочить у випадкове місце.

  3. Боти рухаються

    3а. Якщо ваш бот дає недійсний вихід, він не переміститься

    3б. Ваш бот намагатиметься максимально наблизитися до простору, визначеного результатом (див. Примітку внизу для більш детальної інформації)

    3в. Один напад на сороковуху, лева чи кажана вб'є її

    3d. Напад на іншого бота без ножа завдасть 5 збитків, а 10 - ножем

Правила:

  1. Дотримуйтесь загальних мов, які можна запустити на OS X або Linux.

  2. Ви можете за бажанням записати у файл та не перевищувати 1 кбіт даних

Оцінка:

Боти будуть знаходитися в печері лише до тих пір, поки не залишиться лише один, або поки не пройде 50 оборотів, залежно від того, що відбудеться раніше. Ваш бот буде оцінюватися за сумою кількості золотих монет, які він зібрав, і скільки обертів він тривав.

Код контролера можна завантажити для тестування тут (зробіть папку під назвою "bots" в тому самому каталозі, в який ви завантажуєте, і помістіть бота всередину "bots"). Для його запуску вам знадобиться NumPy. Сміливо копайте це, але вам доведеться вибачити безлад ...

Ось код для випадкового бота:

#!/usr/bin/python
import random as r

a = ['M','A','H']
d = ['NN','NE','EE','SE','SS','SW','WW','NW']

print(a[r.randint(0,2)]+d[r.randint(0,7)]+a[r.randint(0,2)]+d[r.randint(0,7)])

**** Ваш бот завжди рухатиметься в загальному напрямку, яке визначає ваш вихід, але якщо його перешкоджає скеля або стіна, точний напрямок залежить від обставини. Наприклад, якщо ваш бот прилягає до стіни так:

---
}--
Y--
---
---

і ваш вихід

MNWMSW

ваш бот переміститься на простір вниз. Він не міг рухатися на північ чи захід, тому цей рух не мав ефекту. Він міг рухатись Півднем (та й робив), але не міг рухатись Заходом. Однак, якщо ваш бот спробував переміститися на північний схід, він пішов би безпосередньо в цей простір (діагональний рух діагональний, а не процедурний)

Таблиця лідерів

Це середні бали 4 гри.

The bot of Survival:    54.75
Coward:                 52.25
Pufferfish:             50.00
Randombot:              50.00
Indiana Jones:          47.50
TheoremBot:             46.50

Скільки здоров'я має кожен бот? А як виглядає край печери?
Conor O'Brien

Вони починаються з 20 і можуть зібрати скільки завгодно. Додано цю інформацію вище
The Beanstalk

Краї порожнини не позначені, ваша програма отримає лише ті шматочки, якими ви могли б ходити.
The Beanstalk

Ви справді не знаєте свого здоров’я?
pppery

Не могли б ви ввести довжину та ширину зору бота?
LegionMammal978

Відповіді:


4

Індіана Джонс, Python 2

Цей бот нічого не боїться. Це спробує дістати золото; і якщо він не зможе знайти жодного, він спробує вдарити ножами противників.

#!/usr/bin/env python
import sys
import random
data = sys.stdin.readlines()
health, gold, turns, poison_remaining, pit_remaining, revealer, knife = eval(data[0])
lines = data[1:]

myloc = [-1, -1]

width, height = len(lines[0]), len(lines)

for y, line in enumerate(lines):
    if line.find('Y')>-1:
        myloc = [line.index('Y'), y]
if myloc[0]<width/2:
    padding = int(width/2-myloc[0])
    lines = ['-'*padding+line for line in lines]
    myloc[0]+=padding
elif myloc[0]>width/2+1:
    padding = int(myloc[0]-width/2-1)
    lines = [line+'-'*padding for line in lines]

if myloc[1]<height/2:
    padding = int(height/2-myloc[1])
    lines = ['-'*width]*padding + lines
    myloc[1]+=padding
elif myloc[1]>height/2+1:
    padding = int(myloc[1]-height/2-1)
    lines = lines + ['-'*width]*padding

uddirections = {1:'N',0:'',-1:'S'}
lrdirections = {1:'E',0:'',-1:'W'}

golds = {}
for y, line in enumerate(lines):
    if 'G' in line:
        x = line.index('G')
        direction = ((uddirections[max(min(myloc[1]-y,1),-1)]+lrdirections[max(min(x-myloc[0],1),-1)])*2)[:2]
        distance = max(abs(myloc[0]-x), abs(myloc[1]-y))
        golds[distance] = direction

bots = {}
for y, line in enumerate(lines):
    if '@' in line:
        x = line.index('@')
        direction = ((uddirections[max(min(myloc[1]-y,1),-1)]+lrdirections[max(min(x-myloc[0],1),-1)])*2)[:2]
        distance = max(abs(myloc[0]-x), abs(myloc[1]-y))
        bots[distance] = direction

foods = {}
for y, line in enumerate(lines):
    if 'F' in line:
        x = line.index('F')
        direction = ((uddirections[max(min(myloc[1]-y,1),-1)]+lrdirections[max(min(x-myloc[0],1),-1)])*2)[:2]
        distance = max(abs(myloc[0]-x), abs(myloc[1]-y))
        foods[distance] = direction

knives = {}
for y, line in enumerate(lines):
    if 'K' in line:
        x = line.index('K')
        direction = ((uddirections[max(min(myloc[1]-y,1),-1)]+lrdirections[max(min(x-myloc[0],1),-1)])*2)[:2]
        distance = max(abs(myloc[0]-x), abs(myloc[1]-y))
        knives[distance] = direction

if golds:
    direction = golds[min(golds.keys())]
elif not knife and knives:
    direction = knives[min(knives.keys())]
elif health<20 and foods:
    direction = foods[min(foods.keys())]
elif bots and knife:
    direction = bots[min(bots.keys())]
    if min(bots.keys())==1:
        print ('A'+direction)*2
        sys.exit(0)
    elif min(bots.keys())==2:
        print 'M'+direction+'A'+direction
        sys.exit(0)
else:
    print ('M'+random.choice('NS')+random.choice('NEWS'))*2
    sys.exit(0)
print ('M'+direction)*2

Просто потрібно було змінити одне, щоб це було спрацьоване - line.index('Y')викине помилку, якщо "Y" не буде в рядку, але line.find('Y')поверне -1, якщо "Y" не буде в рядку. Інакше це чудово!
The Beanstalk

Ви іноді виводите бот тростину MSNMSN, яка недійсна.
pppery

3

Трус, пітон3

Трус завжди біжить від потенційних загроз.

Однак, якщо він почуватиметься супер сильним, він раптом почне бігти і колоти все біля себе.

Проблема поточної реалізації полягає в тому, що команди переміщення видаються без знання, чи це перший, чи другий хід.

#!/usr/bin/env python3.4

import sys, random


class Coward():
  """
  A coward always runs from potential threats.

  However, if he feels super strong, he will suddenly run amok 
  and stab everything near him.  
  """
  def __init__(self, hp, gold, turn, poison, pit, revealer, knife):
    self.hp=int(hp)
    self.gold=int(gold)
    if knife=="True": self.knife=True
    else: self.knife=False    
    self.pit=int(pit)
    self.poison=int(poison)

  def readGrid(self, grid):
    self.grid=grid.split("\n")
  @property
  def _confidence(self):
    return self.hp+5*self.knife-2*self.poison
  @property
  def _lineOfY(self):
    for i, line in enumerate(self.grid):
      if "Y" in line:
        return i
  @property
  def _colOfY(self):
    return self.grid[self._lineOfY].index("Y")
  @property
  def _maxX(self):
    return len(self.grid)-1
  @property
  def _maxY(self):
    return len(self.grid[0])-1
  def move(self, step):
    d = {'NN':(0,-1),'NE':(1,-1),'EE':(1,0),'SE':(1,1),'SS':(0,1),'SW':(-1,1),'WW':(-1,0),'NW':(-1,-1)}
    c2d={(0,-1):'NN',(1,-1):'NE',(1,0):"EE",(1,1):"SE",(0,1):"SS",(-1,1):"SW",(-1,0):"WW",(-1,-1):"NW"}
    #Don't move into wall/ boulder/ pit
    #print(d, file=sys.stderr)
    for k,v in list(d.items()):
      x=self._lineOfY+v[0]
      y=self._colOfY+v[1]
      #print (k, v ,x , y, file=sys.stderr)
      if x<0 or y<0 or x>self._maxX or y>self._maxY:
        #print ("Out of bounds: ", k, file=sys.stderr)
        del d[k]
      elif self.grid[x][y]=="}" or self.grid[x][y]=="P":
        del d[k]
    #Always avoid bats, and enemys
    for dx in range(-2,3):
      for dy in range(-2,3):
        x=self._lineOfY+dx
        y=self._colOfY+dy
        if x<0 or y<0 or x>self._maxX or y>self._maxY:
          continue;
        if self.grid[x][y] in ["B", "L", "C", "@"]:
          for k in self._toDirection(dx, dy):
            if k in d: del d[k] #Too many threats from all sides can paralyze the Coward: nowhere to go...
    #print(d, file=sys.stderr)
    tomove=[]
    #Neighboring fields
    for dx in [-1,1]:
      for dy in [-1,1]:
        x=self._lineOfY+dx
        y=self._colOfY+dy
        if x<0 or y<0 or x>self._maxX or y>self._maxY:
          continue
        if self.poison>0 and self.grid[x][y]=="W":
          for k,v in d.items():
            if v==(dx,dy):
              tomove.append(k)
        if self.grid[x][y]=="N": #Always go to nurse, even if dangerous
          tomove.append(c2d[(x,y)])
        if self.grid[x][y] in ["F","K","G"]: #Go to Food, Knife or Gold, if save
          for k,v in d.items():
            if v==(dx,dy):
              tomove.append(k)
    #Further away: Go towards food, knife and gold and Nina if save.
    for target in ["N", "F", "G", "K"]:
      for dx in [-2,2]:
        for dy in [-2,2]:
          x=self._lineOfY+dx
          y=self._colOfY+dy
          if x<0 or y<0 or x>self._maxX or y>self._maxY:
            continue
          if self.grid[x][y]==target:
            l=[ k for k in self._toDirection(dx,dy) if k in d]
            if l: tomove.append(random.choice(l))
    s=list(d.keys())
    random.shuffle(s)
    tomove+=s
    try:
      return "M"+tomove[step-1]
    except IndexError:
      return ""
  def attack(self, step):    
    c2d={(0,-1):'NN',(1,-1):'NE',(1,0):"EE",(1,1):"SE",(0,1):"SS",(-1,1):"SW",(-1,0):"WW",(-1,-1):"NW"}
    #If Bot next to you: always attack
    for k,v in c2d.items():
      x=self._lineOfY+k[0]
      y=self._colOfY+k[1]
      if x<0 or y<0 or x>self._maxX or y>self._maxY:
        continue
      if self.grid[x][y]=="@":
        return "A"+v
    #If Bot or monster could come closer: attack potential new position
    attDir={(-2,-2):["NW"], (-2,-1):["NW","WW"], (-2,0):["WW","NW","SW"], (-2,1):["WW","SW"], (-2,2):["SW"],(-1,-2):["NW","NN"], (-1,2):["SW","SS"], (0,2):["SW","SS","SE"],(0,-2):["NW","NN","NE"],(1,-2):["NN","NE"],(1,2):["SS","SE"],(2,-2):["NE"],(2,-1):["NE","EE"], (2,0):["NE","EE","SE"], (2,1):["EE","SE"], (2,2):["SE"]}
    for k,v in attDir.items():
      x=self._lineOfY+k[0]
      y=self._colOfY+k[1]
      if x<0 or y<0 or x>self._maxX or y>self._maxY:
        continue
      if self.grid[x][y] in ["@","L","C","B"]:
        return "A"+random.choice(v)
    return ""
  def _toDirection(self,dx,dy):
    if dx<0:
      if dy<0:
        return ["WW","NW","NN"]
      elif dy==0:
        return ["WW","NW","SW"]
      elif dy>0:
        return ["WW","SW","SS"]
    elif dx>0:
      if dy<0:
        return ["EE","NE","NN"]
      elif dy==0:
        return ["EE","NE","SE"]
      elif dy>0:
        return ["EE","SE","SS"]
    elif dx==0:
      if dy<0:
        return ["NN","NE","NW"]
      elif dy==0:
        return []
      elif dy>0:
        return ["SS","SE","SW"]
  def _nearBat(self):
    for dx in range(-2,3):
      for dy in range(-2,3):
        x=self._lineOfY+dx
        y=self._colOfY+dy
        if x<0 or y<0:
          continue;
        if self.grid[x][y]=="B":
          return True
    return False
  def makeTurn(self):
    try:
      command=""
      #If stuck, just attack
      if self.pit:
        command+=self.attack(1)+self.attack(2)
      #Always run from bats
      if self._nearBat:
        command+=self.move(1)+self.move(2)
      #If high-confidence: attack
      if self._confidence>30:
        command+=self.attack(1)+self.attack(2)
      #Else: Move somewhere
      command+=self.move(1)+self.move(2)
      #Just in case, two random attacks
      d = ['NN','NE','EE','SE','SS','SW','WW','NW']
      a=random.choice(d)
      b=random.choice([ x for x in d if x!=a])
      command+="A"+a+"A"+b
      return command[:6]
    except Exception as e:
      #print (e, file=sys.stderr)
      #Attacking is better than nothing
      d = ['NN','NE','EE','SE','SS','SW','WW','NW']
      a=random.choice(d)
      b=random.choice([ x for x in d if x!=a])
      return "A"+a+"A"+b


info=sys.stdin.readline()
grid=sys.stdin.read()
info=info.split(",")
bot=Coward(*info)
bot.readGrid(grid)
t=bot.makeTurn()
#print(t, file=sys.stderr)
print(t)

3

Бот виживання - Python 2

from __future__ import print_function
health,gold,survived,poison,pit,revealer,knife = input()
if pit:
    exit()
#Yes, this is python 2, despite the use of input()
lines = []
try:
    while True:
        lines.append(raw_input())
except EOFError:
    pass
CMOVES={"NW":(-1,-1),"NN":(-1,+0),"NE":(-1,+1),
        "WW":(+0,-1),             "EE":(-0,+1),
    "SW":(+1,-1),"SS":(+1,+0),"SE":(+1,+1),
}
MOVES={v:k for k,v in CMOVES.iteritems()}
import sys
def get_your_pos():
    for row,line in enumerate(lines):
        for col,square in enumerate(line):
            if square == "Y":
                return row,col
    raise ValueError("Your bot is not present.")
def isnearby(thing,p=None):
    your_pos = p or get_your_pos()
    for move in MOVES:
        yp = your_pos[0]+move[0],your_pos[1]+move[1]
        try:
            if yp[0] >= 0 and yp[1] >= 0 and lines[yp[0]][yp[1]] == thing:
                return move
        except IndexError:
            #Edge of cavern
            pass
for turn in range(2):
    import random
    nprio = .5
    if health > 25:
        nprio -= .2
    elif health < 10:
        nprio += .3
    if poison:
        nprio += .18
    #heal
    motive = how = None
    if random.random() < nprio:
        nurse = isnearby("N")
        if nurse:
            motive = "M"
            how = MOVES[nurse]
        elif random.random() < nprio:
            food = isnearby("F")
            if food:
                motive = "M"
                how = MOVES[food]
    #cure poison
    if poison and not motive:
        water = isnearby("W")
        if water:
            motive = "M"
            how = MOVES[water]
    if not motive:
        #Kill lions, bats, and centipedes
        for animal in ("L","B","C"):
            animal = isnearby(animal)
            if animal:
                motive = "A"
                how = MOVES[animal]
                y = get_your_pos()
                y = y[0]+animal[0],y[1]+animal[1]
                lines = map(list,lines)
                lines[y[0]][y[1]] = "-"
                break
        else:
            #Pick up knives
            if not knife:
                knife = isnearby("K")
                if knife:
                    motive = "M"
                    how = MOVES[knife]
            #Attack other bots
            else:
                prey = isnearby("@")
                if prey:
                    motive = "A"
                    how = MOVES[prey]
    #Get gold
    gold = isnearby("G")
    if gold and not motive:
        motive = "M"
        how = MOVES[gold]
    def isvalidmove(c):
        c = CMOVES[c]
        y = get_your_pos()
        y=(y[0]+c[0],y[1]+c[1])
        if y[0] >= 0 and y[1] >= 0:
            try:
                lines[y[0]][y[1]]
            except LookupError:
                pass
            else:
                return True
    if turn and not motive:
        motive = "M"
        while not (how and how not in (isnearby("}"),isnearby("P"),isnearby("@"))\
              and isvalidmove(how)):
            how = random.choice(CMOVES.keys())
    if not motive:break
    if not turn and motive == "M":
        lines = map(list,lines)
        yp = get_your_pos()
        lines[yp[0]][yp[1]] = "-"
        yp=[yp[0]+CMOVES[how][0],yp[1]+CMOVES[how][1]]
        lines[yp[0]][yp[1]] = "Y"
    print(motive+how,end="")
else:
    exit()
#Nothing found on first move
def isvaguelynearby(thing):
    your_pos = get_your_pos()
    for move in MOVES:
        yp = your_pos[0]+move[0],your_pos[1]+move[1]
        try:
            if yp[0] >= 0 and yp[1] >= 0 and board[yp[0]][yp[1]] != "P":
                dest = isnearby(thing,yp)
                if dest:
                    return move,dest
        except IndexError:
            #Edge of cavern
            pass
if random.random() < nprio:
    dests = isvaguelynearby("N")
    if not dests and random.random() < nprio:
        dests = isvaguelynearby("F")
    if dests:
        m1,m2 = MOVES[dests[0]],MOVES[dests[1]]
        print("M" + m1 + "M" + m2)
        exit()
dests = (poison and isvaguelynearby("W")) or (not knife and isvaguelynearby("K"))\
    or isvaguelynearby("G")
prey = isvaguelynearby("L") or isvaguelynearby("B") or isvaguelynearby("C") or \
       (knife and isvaguelynearby("@"))
if dests:
    m1,m2 = MOVES[dests[0]],MOVES[dests[1]]
    print("M" + m1 + "M" + m2)
elif prey:
    m1,m2 = MOVES[prey[0]],MOVES[prey[1]]
    print("M" + m1 + "A" + m2)
else:
    how = None
    while not (how and how not in     (isnearby("}"),isnearby("P"),isnearby("@"))\
          and isvalidmove(how)):
        how = random.choice(CMOVES.keys())
    print("M"+how,end="")
    lines = map(list,lines)
    yp = get_your_pos()
    lines[yp[0]][yp[1]] = "-"
    yp=[yp[0]+CMOVES[how][0],yp[1]+CMOVES[how][1]]
    lines[yp[0]][yp[1]] = "Y"
    while not (how and how not in (isnearby("}"),isnearby("P"),isnearby("@"))\
          and isvalidmove(how)):
            how = random.choice(CMOVES.keys())
    print("M"+how)

Редагувати: додано краще уникання ями.


2

Pufferfish, Python 3+

Я просто та людина.

#!/usr/bin/env python3.4
import random
def select():
 return "A"+["NN","NE","EE","SE","SS","SW","WW","NW"][random.randint(0,7)]
print(select()+select())

Цей бот має на меті самозабезпечення. Пізніше я можу додати пошуки гольфу, якщо матиму час.
Conor O'Brien

Це зробить ваш код трохи довше, але Pufferfish може атакувати двічі за один і той же поворот, якщо він хотів бути більш смертельним
The Beanstalk

@TheBeanstalk О, солодкий!
Conor O'Brien

Ви розумієте, що цей бот ніколи не здобуде жодного золота, і не всі інші боти будуть бродити в його "вбивство аури"
pppery

@ppperry я розумію це; це було головним чином для того, щоб м'яч котився; це не вигравати, а зробити життя трохи складніше. Як і в, Black Hat Man
Conor O'Brien
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.