To Życie, Jim, ale nie takie, jakie znamy

58

Prawdopodobnie znasz Conway's Game of Life , słynny automat komórkowy wymyślony przez matematyka Johna Conwaya. Życie to zbiór zasad, które razem pozwalają na symulację dwuwymiarowej planszy komórek. Reguły decydują, które komórki na planszy żyją, a które umierają. Przy odrobinie wyobraźni można powiedzieć, że Life to gra dla zero graczy: gra, której celem jest znalezienie wzorów o interesującym zachowaniu, takich jak słynny szybowiec.

Szybowiec

Gra dla zero graczy ... Do dziś. Masz napisać program, który gra w Game of Life - i gra w nią, aby wygrać, w stylu Króla Wzgórza. Twój przeciwnik (liczba pojedyncza) oczywiście próbuje zrobić to samo. Zwycięzcą jest albo ostatni bot z dowolnymi żywymi komórkami, albo gracz z największą liczbą żywych komórek po 10000 pokoleniach.

Zasady gry

Zasady są prawie takie same jak normalne (B3 / S23) Życie:

  • Żywa komórka z mniej niż dwoma przyjaznymi sąsiadami umiera z głodu.
  • Żyje komórka z dwoma lub trzema przyjaznymi sąsiadami.
  • Żywa komórka z więcej niż trzema przyjaznymi sąsiadami umiera z powodu przeludnienia.
  • Martwa komórka z dokładnie trzema sąsiadami tego samego gracza ożywa, aby walczyć o tego gracza, pod warunkiem, że nie ma wrogich sąsiadów .

... ale po każdym pokoleniu zarówno ty, jak i twój przeciwnik macie możliwość interwencji. Możesz obudzić maksymalnie 30 komórek, aby o ciebie walczyć. (Kto jest pierwszy, decyduje serwer).

Plansza jest kwadratem komórek (x, y). Wszystkie pola są początkowo martwe. Granice nie zawijają się (nie jest to świat w kształcie torusa) i są na stałe martwe.

To jest konkurs w duchu Battlebots i Core Wars . Istnieje centralny serwer, który będzie uruchamiał boty i można go znaleźć tutaj

Protokół

Serwer areny mówi prostym protokołem JSON komunikowanym przez argv

Gdzie Wartości są łańcuchem zakodowanym w JSON

  • y_size: maksymalne y współrzędnych płytek, zanim znikną
  • x_size: maksymalna x współrzędnych płytek, zanim znikną
  • tick_id: bieżący numer tiku
  • board: słownik z kluczami w postaci „(y, x)” i wartościami w postaci bot_id(int)
  • bot_id: płytki na planszy o tym identyfikatorze są twoje

Przykład:

 {"y_size":2000,"x_size":2000,"board":{},"bot_id":1,"tick_id":1}

Mówienie serwerowi o swoim wyborze:

  • Wyślij serwerowi listę kafelków, aby zmienić kolor.
  • Tylko te, które są puste, zostaną zmienione
  • Format zagnieżdżonej listy współrzędnych
    • [[0,0], [0,1], [100,22]...]

UWAGA: Twój bot wcale nie musi aktualizować kafelków - serwer sam dokonuje aktualizacji

Zasady konkurencji

  • Jeśli twoja implementacja nie postępuje zgodnie z protokołem, jego kolej przepadnie; Serwer nie przyjmie żadnej zmiany stanu
  • Nie możesz świadomie skorzystać z usterki na serwerze areny.
  • Niech twoja AI decyduje o ruchach w rozsądnym czasie. Prześlij swój następny ruch tak szybko, jak to możliwe.
  • Wreszcie, proszę bądź miły dla serwera. To jest dla twojej przyjemności.
  • Nieprzestrzeganie tych zasad może prowadzić do dyskwalifikacji.
  • W przypadku remisu obaj gracze dodają 1 wygraną do swojej sumy

Samodzielne sterowanie kontrolerem

Źródło kontrolera można znaleźć tutaj . Istnieją 2 sposoby uruchamiania kontrolera:

  • Tryb zawodów (terminal)
    • Skonfigurować python3 get_answers.py
    • Przeprowadź konkurencję all v all z każdym botem, który zmierzy się ze sobą.
  • Tryb testowy (GUI)
    • Biegać python3 nice_gui.py
    • Kliknij Pull Answers
    • Jeśli chcesz dodać własną odpowiedź, aby wypróbować ją przed opublikowaniem, kliknij File -> Add manual answeri znajdź plik oraz wybierz język, w którym jest napisany.
    • Jeśli twój język nie jest obecny, wyślij mi ping i postaram się go zainstalować na serwerze, uruchomię go (instrukcje instalacji i uruchamiania również byłyby fajne!)
    • Wybierz 2 boty, aby ze sobą konkurować
    • Kliknij Run
    • Oglądaj grę...
  • Instalacja
    • Wymaga python3
    • get_answers wymaga bs4 i html5lib
    • kontroler wymaga sposobu uruchamiania plików .sh (MinGW w systemie Windows)

Przykładowy obraz aplikacji

Punktacja

Bot z największą liczbą wygranych od 12/07/2016(12 lipca) 14/07/2016 (14 lipca, nie mógł wymyślić, jak uruchomić bota) wygrywa.


W tym czacie można poprosić o pomoc z kontrolerem / GUI


To pytanie jest rozwijane od 2014 r. I było najczęściej wybieranym pytaniem w piaskownicy. Specjalne podziękowania kierujemy do Wander Nauta (oryginalny autor i koncepcji), PPCG Chat (komentarze i pomoc) i każdy, kto skomentował w piaskownicy postu (więcej uwagi).

niebieski
źródło
25
Huh, myślałem, że to nigdy nie wyjdzie z piaskownicy. Wspaniały!
Luis Mendo
Literówka: 12/06/2016 (12 lipca)
Luis Mendo
4
+1. Zasługujesz na nagrodę AED za wyniesienie tego wielkiego pytania z piaskownicy!
agtoever
1
@ KevinLau-notKenny och, dobrze. Czy możesz uruchomić polecenie w pliku?
Rɪᴋᴇʀ
1
@Magenta Kiedy je dostaję (całkowicie o tym zapomniałem, mimo że było to w ciągle otwartej zakładce), uruchamiam je teraz
Blue

Odpowiedzi:

4

Python 3, Exploder

Rozstawia małe wybuchacze wokół tego miejsca, bez względu na to, czy jest tam już blok.

from random import randint
import sys,json,copy
q=json.loads(sys.argv[1])
x=q["x_size"];y=q["y_size"];F=[[0,1],[1,0],[1,1],[1,2],[2,0],[2,2]];D=[]
for g in [0]*5:
 X=randint(0,x);Y=randint(0,y);A=copy.deepcopy(F)
 for C in A:C[0]+=Y;C[1]+=X
 D+=A
print(D)
Magenta
źródło
1
Nie mogę uwierzyć, że po całej mojej pracy nad ustawieniami blokujących przełączniki na nieokreślony wzrost i systemem specjalnie zbudowanym w celu zniszczenia struktur wzrostu, prosty system oparty na eksplodatorze pokonał kopalnię w walce: o
Wartość Ink
Nie wiem też, jak to działa, ponieważ nie mogę uruchomić kontrolera z jakiegokolwiek powodu.
Magenta
8

Ruby, InterruptingBlockMaker

Zamiast inicjować szybowce, takie jak TrainingBot, próbuje stworzyć maszynę do przełączania bloków 5x5, jak wspomniano na Wikipedii, w losowym punkcie w labiryncie. Następnie, wraz z pozostałymi aktywacjami, po prostu znajduje punkty wroga i próbuje zasypać pobliskim obszarem komórkami, próbując przerwać ich wzrost i być może zepsuć ich wzorce. Twoje komórki umrą w następnym pokoleniu, ale być może zatrzymały też pewien wzrost, aby spowolnić przeciwnika!

v2: Zoptymalizowana nieznacznie (?), aby spróbować zminimalizować limity czasu.

v3: Zoptymalizowany kod przerwania do wstępnego próbkowania podzestawu aktywnych bloków przed odrzuceniem naszych własnych lokalizacji komórek, aby jeszcze bardziej zapobiegać przekroczeniom limitu czasu kosztem pewnej skuteczności w atakach z przerwaniem komórki.

require 'json'

class Range
  def product range2
    self.to_a.product range2.to_a
  end
end

args = JSON.parse(ARGV[0])
bot_id = args["bot_id"]
width  = args["x_size"]
height = args["y_size"]
board  = args["board"]

generator = [[2,2], [2,3], [2,6], [3,2], [3,5], [4,2], [4,5], [4,6], [5,4], [6,2], [6,4], [6,5], [6,6]]

targets = []

iterations = 50
gen_location = nil
while !gen_location && iterations > 0
  y = rand height - 9
  x = rand width  - 9
  temp = (0...9).product(0...9).map{|_y, _x| [y + _y, x + _x]}
  if temp.all?{|_y,_x| !board["(#{y},#{x})"]}
    gen_location = temp
    targets += generator.map{|_y, _x| [y + _y, x + _x]}
  end

  iterations -= 1
end

enemies = board.keys.sample(100).reject {|k| board[k] == bot_id}
interrupts = []
enemies.each do |location|
  y, x = location.scan(/\d+/).map &:to_i
  interrupts |= ((y-1)..(y+1)).product((x-1)..(x+1)).reject{|y, x| gen_location.include?([y,x]) || board["(#{y},#{x})"]}
end

targets += interrupts.sample(30 - targets.size)

puts JSON.dump(targets)
Wartość tuszu
źródło
@muddyfish dzięki, że to naprawiło! Teraz jedynym problemem jest to, że polecenia wiersza poleceń systemu Windows mają ustalony na stałe limit 8191, co oznacza, że ​​w pewnym momencie symulacji boty ulegną awarii, ponieważ nie będą w stanie przeanalizować obciętego ciągu JSON. Jest to problem z systemem operacyjnym, więc myślę, że muszę sprawdzić Linuxa w chmurze lub coś innego, aby przetestować mojego bota ~
Value Ink
@muddyfish Wspomniałem już, że Windows ma problemy z powodu limitu wiersza poleceń, ten ostatni błąd był na Cloud9, który rzekomo jest Linux-em. Jak radzi sobie mój bot na twoim Linux-ie (skoro sugerowałeś, że go masz)?
Wartość tuszu
Okazuje się, że tego nie popełniłem, ale liczby bot_scorepokazują, ile zwycięstw ma każdy bot w stosunku do innych botów
Blue
W porządku, dzięki! Niestety, Cloud9 rzeczywiście nie ma GUI, a Windows nadal nie może uruchomić symulacji bez przekroczenia limitu poleceń, ale przynajmniej rzuciłem okiem na to, jak radzą sobie boty. Widzę też, że mój bot walczy ze sobą do samego końca, ponieważ atakują się nawzajem i zapobiegają wystarczającemu wzrostowi, aby przekroczyć limit postaci, chociaż czasem to się kończy ...
Wartość Ink
4

Python 2, TrainingBot

Ponieważ każdy potrzebuje jednego z nich!

import random, copy
import sys, json

args = json.loads(sys.argv[1])
bot_id = args["bot_id"]
x_size = args["x_size"]
y_size = args["y_size"]
cur_tick = args["tick_id"]
board = args["board"]

glider = [[1,2],[2,1],[0,0],[0,1],[0,2]]

x_add = random.randrange(x_size)
y_add = random.randrange(y_size)
new_glider = copy.deepcopy(glider)
for coord in new_glider:
    coord[0]+=y_add
    coord[1]+=x_add
move = new_glider
print json.dumps(move)
niebieski
źródło
4

Java, Troll Bot

Troll Bot pomyślał o tym i zdaje sobie sprawę, że NIE dba o wroga. W rzeczywistości po prostu przekręca te fabryki, aby losowo produkować więcej swoich ludzi na całej mapie. Po chwili zdał sobie sprawę, że wszelkie dodatkowe komórki najlepiej wykorzystać w skupiskach. Te bloki czterech komórek skleją się ze sobą i zatrzymają szybowce na swoich torach! Nie uważa, żeby po prostu walczył. Jest także wielkim zwolennikiem pełnego programowania obiektowego. Troll zakłada również, że kable są w formacie y, x i prosi o przetestowanie. Wystarczy umieścić go w pliku o nazwie „TrollBot.java”, a on zostanie ustawiony!

package trollbot;

/**
 *
 * @author Rohans
 */
public class TrollBot{
public static class coord{
    public int x;
    public int y;
    public coord(int inX,int inY){
        x = inX;
        y = inY;
    }
    @Override
    public String toString(){
        return"["+x+","+y+"]";
    }
}
    /**
     * Input the JSON as the first cla
     * @param args the command line arguments
     */
    public static void main(String[] args) {
       String JSON="{\"bot_id\":1,\"y_size\":1000,\"x_size\":1000,\"board\":{}}";
    String[] JArray=args[0].split(",");
       int botId=Integer.parseInt(JSON.charAt(10)+"");
    int xSize=Integer.parseInt(JArray[2].substring(JArray[2].indexOf(":")+1));
    int ySize=Integer.parseInt(JArray[1].substring(JArray[1].indexOf(":")+1));
    int[][] board = new int[xSize][ySize];//0 indexed
//todo: parse the board to get an idea of state
    String soldiers="[";    
//for now just ignore whats on the board and put some troll cells on
    //Attempts to create 3 10 cells factories of cells, hoping it does not place it on top of allies
    //Then puts random 2/2 blocks
  boolean[][] blockspam=new boolean[10][8];
  blockspam[7][1]=true;
  blockspam[5][2]=true;
  blockspam[7][2]=true;
  blockspam[8][2]=true;
  blockspam[5][3]=true;
  blockspam[7][3]=true;
  blockspam[5][4]=true;
  blockspam[3][5]=true;
  blockspam[1][6]=true;
  blockspam[3][6]=true;
  for(int z=0;z<3;z++){
     int xOffSet=(int) (Math.random()*(xSize-11));
     int yOffSet=(int) (Math.random()*(ySize-9));
     //stay away from edges to avoid odd interactions
     for(int i=0;i<blockspam.length;i++){
         for(int j=0;j<blockspam[i].length;j++){
             if(blockspam[i][j])
             soldiers+=new coord(j+yOffSet,i+xOffSet).toString()+",";
         }
     }
  }
  soldiers=soldiers.substring(0,soldiers.length()-1);
  for(int i=0;i<8;i++){
            int y=(int ) (Math.random()*(ySize-1));
            int x = (int) (Math.random()*(xSize-1));
      soldiers+=new coord(y,x).toString()+",";
                          soldiers+=new coord(y+1,x).toString()+",";
                          soldiers+=new coord(y,x+1).toString()+",";
                          soldiers+=new coord(y+1,x).toString()+",";

  }
  soldiers+="\b]";

  System.out.println(soldiers);
  //GO GO GO! Lets rule the board
    }

}
Rohan Jhunjhunwala
źródło
3

Python 3, RandomBot

Ten bot ma problemy z podejmowaniem inteligentnych decyzji, ale przynajmniej wie, aby nie próbować umieszczać rzeczy nad innymi. Będzie losowo tworzyć szybowce, łodzie, C / 2 Orthagonal i bloki 2x2 o różnych orientacjach, zapewniając, że po ich umieszczeniu nie będą się one nakładać na coś innego, sojusznika lub wroga.

Ten bot nie był testowany, ponieważ otrzymuję różnego rodzaju błędy podczas próby uruchomienia GUI. Ponadto użyłem TrainingBot jako podstawy i po prostu edytuję, więc wszelkie podobieństwa w kodzie są prawdopodobnie z tego powodu.

import random, copy
import sys, json
args = json.loads(sys.argv[1])
bot_id = args["bot_id"]
x_size = args["x_size"]
y_size = args["y_size"]
board = args["board"]
occupied = [tuple(key) for key,value in iter(board.items())]
cellsleft=30
move=[]
choices = [[[1,2],[2,1],[0,0],[0,1],[0,2]],
           [[0,0],[0,1],[1,1],[1,0]],
           [[0,1],[1,0],[0,2],[0,3],[1,3],[2,3],[3,3],[4,3],[5,2],[5,0]],
           [[0,0],[1,0],[0,1],[2,1],[2,2]]]
while cellsleft>0:
    x_add = random.randrange(x_size)
    y_add = random.randrange(y_size)
    new_glider = copy.deepcopy(random.choice(choices))
    randomdirection = random.choice([[1,1],[1,-1],[-1,1],[-1,-1]])
    maxy=max([y[0] for y in new_glider])
    maxx=max([x[1] for x in new_glider])
    for coord in new_glider:
        coord[0]=coord[0]*randomdirection[0]+y_add
        coord[1]=coord[1]*randomdirection[1]+x_add
        cellsleft-=1
    set([tuple(x) for x in new_glider]) 
    if not set([tuple(x) for x in new_glider]) & (set(occupied)|set([tuple(x) for x in move])) and cellsleft>0:
        if min(y[0] for y in new_glider)<0: new_glider = [[y[0]+maxy,y[1]] for y in new_glider]
        if min(y[1] for y in new_glider)<0: new_glider = [[y[0],y[1]+maxx] for y in new_glider]
        move += new_glider
    elif set([tuple(x) for x in new_glider]) & (set(occupied)|set([tuple(x) for x in move])):
        cellsleft+=len(new_glider)

print(json.dumps(move))
Steven H.
źródło
1
GUI najprawdopodobniej zawiedzie z powodu twojego print(sys.argv[1])linii 3, która zakłóca wynik (symulator oczekuje tylko ciągu współrzędnych, które chcesz obudzić). Ponadto w ostatnim wierszu programu brakuje pliku zamykającego.
Wartość tuszu
@ KevinLau-notKenny GUI zawiódł także bota szkoleniowego i bota Ruby. Usunąłem jednak tę linię i dodałem ją ponownie w zamykającym paren (myślę, że ten ostatni był błędem kopiuj-wklej).
Steven H.
Z jakiego systemu operacyjnego korzystasz i jakie błędy pojawiają się w wierszu poleceń po uruchomieniu? Obecnie znany jest błąd polegający na tym, że system Windows nie może poprawnie uruchomić karty SIM, ponieważ argumenty przekazywane przez linię poleceń są obcinane, gdy przekraczają limit znaków w linii poleceń wynoszący około 8000.
Wartość Ink
@ KevinLau-notKenny Korzystam z systemu Windows 10 i dostałem ... no cóż, wiele błędów. Pierwszą rzeczą było to, że BeautifulSoup nie chciała znaleźć html5lib, a następnie nie znalazła folderu zawierającego wszystkie boty (musiałem zmienić kod dla obu z nich), a od tego czasu uruchomienie jednego z botów Python skutkowało kodem powrotu innym niż 0 1.
Steven H.
System Windows nadal nie może uruchomić kodu, jeśli na ekranie jest zbyt wiele aktywnych komórek ... Ale jeśli chodzi o inne błędy, może to być spowodowane tym, że TrainingBot chce Python 2?
Wartość tuszu
3

Python, GuyWithAGun

On jest facetem, ma broń; on jest zły. Po prostu rzuca wszędzie pistolety szybowcowe, bez względu na to, co robią inni

import random, copy
import sys, json

args = json.loads(sys.argv[1])
bot_id = args["bot_id"]
x_size = args["x_size"]
y_size = args["y_size"]
tick_id = args["tick_id"]
board = args["board"]

start_squares = [[0,5],[2,5],[1,6],[2,6],
                 [35,3],[36,3],[35,4],[36,4]]
gun = [[11,5],[11,6],[11,7],
       [12,4],[12,8],
       [13,3],[13,9],
       [14,3],[14,9],
       [15,6],
       [16,4],[16,8],
       [17,5],[17,6],[17,7],
       [18,6],
       [21,3],[21,4],[21,5],
       [22,3],[22,4],[22,5],
       [23,2],[23,6],
       [25,1],[25,2],[25,6],[25,7]]

templates = [start_squares, gun]

def add_squares(pos, coords):
    new_squares = copy.deepcopy(coords)
    for coord in new_squares:
        coord[0]+=pos[0]
        coord[1]+=pos[1]
    return new_squares

def get_latest_pos():
    seed, template_id = divmod(tick_id, 2)
    random.seed(seed)
    cur_pos = [random.randrange(y_size),
               random.randrange(x_size)]
    cur_template = templates[template_id]
    try:
        return add_squares(cur_pos, cur_template)
    except IndexError:
        return []

move = get_latest_pos()

print json.dumps(move)
niebieski
źródło
2

Python 3, SquareBot

Stawia wszędzie kwadraty - może

Kwadraty są obiektami statycznymi w życiu - nie poruszają się. Jeśli więc umieszczę wokół tego miejsca wystarczająco dużo obiektów obojętnych, szybowce i eksplozje, które stworzą inni, prawdopodobnie zostaną zablokowane lub przynajmniej wytłumione.

-Adaptowano z TrainingBot

from random import randint
import sys,json,copy
args=json.loads(sys.argv[1])
x=args["x_size"];y=args["y_size"]
square=[[0,0],[0,1],[1,0],[1,1]];D=[]
for g in range(7):
 X=randint(0,x);Y=randint(0,y)
 A=copy.deepcopy(square)
 for C in A:C[0]+=Y;C[1]+=X
 D+=A
print(D)

Chociaż mam problem z przetestowaniem tego

Magenta
źródło
Mogę potwierdzić, że ten bot faktycznie robi to, co powinien - i pomógł mi znaleźć i naprawić błąd w kontrolerze
Blue