É a vida, Jim, mas não como a conhecemos

58

Você provavelmente conhece o Jogo da Vida de Conway , o famoso autômato celular inventado pelo matemático John Conway. A vida é um conjunto de regras que, juntas, permitem simular uma placa bidimensional de células. As regras decidem quais células no quadro vivem e quais morrem. Com alguma imaginação, você poderia dizer que Life é um jogo de zero jogadores: um jogo com o objetivo de encontrar padrões com comportamentos interessantes, como o famoso planador.

Planador

Um jogo de zero jogadores ... Até hoje. Você deve escrever um programa que jogue o Jogo da Vida - e jogue para vencer, no estilo King of the Hill. Seu oponente (singular), é claro, tenta fazer o mesmo. O vencedor é o último bot com células vivas ou o jogador com mais células vivas após 10000 gerações.

Regras do jogo

As regras são quase as mesmas da vida normal (B3 / S23):

  • Uma célula viva com menos de dois vizinhos amigos morre de fome.
  • Uma célula viva com dois ou três vizinhos amigos sobrevive.
  • Uma célula viva com mais de três vizinhos amigos morre de superpopulação.
  • Uma célula morta com exatamente três vizinhos do mesmo jogador ganha vida para lutar por esse jogador, desde que não haja vizinhos inimigos .

... mas após cada geração, você e seu oponente têm a oportunidade de intervir. Você pode acordar até um máximo de 30 células para lutar por você. (Quem vai primeiro é decidido pelo servidor.)

O quadro é um quadrado de células (x, y). Todos os quadrados estão inicialmente mortos. As bordas não se enrolam (não é um mundo em forma de toro) e estão permanentemente mortas.

Este é um concurso no espírito de Battlebots e Core Wars . Existe um servidor central que irá executar bots e pode ser encontrado aqui

Protocolo

O servidor arena fala um protocolo JSON simples comunicado através do argv

Onde Valores é uma sequência codificada em JSON

  • y_size: o máximo de y cordões de peças antes que desapareçam
  • x_size: o máximo x cordões de peças antes que desapareçam
  • tick_id: o número atual do tick
  • board: um dicionário com chaves no formato '(y, x)' e valores no formato bot_id(int)
  • bot_id: as peças no quadro com esse ID são suas

Exemplo:

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

Dizendo ao servidor sua escolha:

  • Envie ao servidor uma lista de peças para mudar para a sua cor.
  • Somente aqueles que estão vazios serão alterados
  • Formato de lista de cordas aninhadas
    • [[0,0], [0,1], [100,22]...]

NOTA: Seu bot não precisa atualizar os blocos - o servidor faz a atualização por si só

Regras da competição

  • Se sua implementação falhar em seguir o protocolo, a sua vez será perdida; O servidor não assumirá nenhuma mudança de estado
  • Você não tem o direito de tirar proveito de uma falha no servidor da arena.
  • Faça sua IA decidir sobre os movimentos em um momento são. Envie sua próxima jogada o mais rápido possível.
  • Por fim, seja gentil com o servidor. Está lá para sua diversão.
  • Não seguir estas regras pode levar à desqualificação.
  • Em caso de empate, os dois jogadores têm 1 vitória adicionada ao total

Executando o controlador você mesmo

A fonte do controlador pode ser encontrada aqui . Existem 2 maneiras de executar o controlador:

  • Modo de competição (terminal)
    • Setup with python3 get_answers.py
    • Execute uma competição all v all com cada bot colocando-o um contra o outro.
  • Modo de teste (GUI)
    • Corre python3 nice_gui.py
    • Clique Pull Answers
    • Se você quiser adicionar sua própria resposta para experimentá-la antes de postar, clique File -> Add manual answere encontre o arquivo e escolha o idioma em que está escrito.
    • Se o seu idioma não estiver presente, envie-me um ping e tentarei instalá-lo no servidor em que o executarei (as instruções de instalação e execução também serão boas!)
    • Escolha 2 bots para jogar um contra o outro
    • Clique Run
    • Assista o jogo...
  • Instalação
    • Requer python3
    • get_answers requer bs4 e html5lib
    • O controlador requer uma maneira de executar arquivos .sh (MinGW no Windows)

Imagem de exemplo do aplicativo

Pontuação

O bot com mais vitórias a partir de 12/07/2016(12 de julho) 14/07/2016 (14 de julho, não conseguia descobrir como executar um bot) vence.


Ajuda com o controlador / GUI pode ser solicitada nesta sala de bate-papo


Esta pergunta está em desenvolvimento desde 2014 e foi a pergunta mais votada na sandbox. Agradecimentos especiais a Wander Nauta (autor e conceito original), PPCG Chat (comentários e ajuda) e a qualquer pessoa que tenha comentado na caixa de areia (mais comentários).

Azul
fonte
25
Pensei que isso nunca sairia da caixa de areia. Ótimo!
Luis Mendo
Erro de digitação: 12/06/2016 (12 de julho)
Luis Mendo
4
+1. Você merece o prêmio AED por trazer esta ótima pergunta da caixa de areia!
agtoever
11
@ KevinLau-notKenny oh, tudo bem. Você pode executar um comando em um arquivo?
Rɪᴋᴇʀ
11
@ Magenta Quando eu os recebo (eu tinha esquecido completamente disso, mesmo que ele esteja em uma guia constantemente aberta), eu estou executando agora
Blue

Respostas:

4

Python 3, Exploder

Coloca pequenos explosivos ao redor do local, sem levar em conta se já existe um bloco lá.

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
fonte
11
Eu não posso acreditar que, depois de todo o meu trabalho criação de interruptores de tomada de bloco para o crescimento indefinido e um sistema construído especificamente para demolir estruturas de crescimento, um sistema de mina simples baseado em exploder derrotou em combate: o
Valor Ink
Também não sei como funciona, porque não consigo executar o controlador por qualquer motivo.
Magenta
8

Ruby, InterruptingBlockMaker

Em vez de inicializar planadores como o TrainingBot, ele tenta criar uma máquina de troca de blocos 5x5, como mencionado na Wikipedia, em um ponto aleatório no labirinto. Então, com as ativações restantes, ele apenas encontra pontos inimigos e tenta apimentar a área próxima com suas células, na tentativa de impedi-los de crescer e possivelmente atrapalhar seus padrões. Suas células morrerão na próxima geração, mas talvez elas também parem um pouco de crescimento para desacelerar seu oponente!

v2: Otimizado ligeiramente (?) para tentar minimizar o tempo limite.

v3: Código de interrupção otimizado para pré-amostrar um subconjunto de blocos ativos antes de rejeitar nossas próprias localizações de células, para evitar tempos limite ainda mais com o custo de alguma eficácia nos ataques de interrupção de células.

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)
Value Ink
fonte
@muddyfish obrigado, isso foi corrigido! Agora, o único problema é que os comandos da linha de comando do Windows têm um limite codificado de 8191, o que significa que, em um determinado ponto da simulação, os bots falharão por não conseguirem analisar a sequência JSON truncada. É uma questão de SO, então acho que tenho que procurar em uma caixa de nuvem Linux ou algo assim para testar meu bot ~
Value Ink
@muddyfish Eu já mencionei que o Windows tem problemas por causa do limite da linha de comando, esse último erro ocorreu no Cloud9, que é ostensivamente uma caixa do Linux. Como meu bot se sai na sua caixa Linux (desde que você sugeriu que a tinha)?
valor é o mesmo da
Acontece que eu não tinha cometido isso, mas os números bot_scoremostram quantas vitórias cada bot tem contra outros bots #
Blue
Tudo bem, obrigado! Infelizmente, o Cloud9 na verdade não possui uma GUI e o Windows ainda não pode executar a simulação sem quebrar seu limite de comando eventualmente, mas pelo menos eu dei uma breve olhada em como os bots se comportam entre si. Além disso, eu começo a ver a minha luta bot contra si mesmo ao fim algumas vezes porque eles continuam atacando uns aos outros e impedindo o crescimento suficiente para quebrar o limite de caracteres, embora não tempo fora ocasionalmente ...
Valor de tinta
4

Python 2, TrainingBot

Porque todo mundo precisa de um desses!

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)
Azul
fonte
4

Java, Troll Bot

Troll Bot pensou nisso, e ele percebe que NÃO se importa com o inimigo. Na verdade, ele apenas usa essas fábricas para produzir mais de seus homens aleatoriamente em todo o mapa. Depois de um tempo, ele percebeu que qualquer célula adicional é melhor usada em aglomerados. Esses blocos de quatro células irão se unir e parar planadores em suas trilhas! Ele não acha que apenas briga. Ele também é um grande defensor da programação detalhada de objetos. O troll também assume que as cordas estão no formato y, x, e ele está pedindo para ser testado. Basta colocá-lo em um arquivo chamado "TrollBot.java" e ele estará pronto!

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
fonte
3

Python 3, RandomBot

Esse bot tem problemas para tomar decisões inteligentes, mas pelo menos sabe não tentar colocar as coisas em cima de outras. Criará aleatoriamente planadores, barcos, C / 2 Orthagonal s e blocos 2x2 com várias orientações, garantindo que, quando colocados, não se sobreponham a algo mais, aliado ou inimigo.

Este bot não foi testado, pois estou recebendo todos os tipos de erros quando tento executar a GUI. Além disso, usei o TrainingBot como base e apenas editei, portanto, qualquer semelhança no código provavelmente é por causa disso.

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.
fonte
11
A GUI provavelmente está falhando por causa da sua print(sys.argv[1])linha 3, que atrapalha a saída (o simulador espera apenas a sequência de coordenadas que você deseja ativar). Além disso, a última linha do seu programa está faltando um ponto final.
Valor de tinta
@ KevinLau-notKenny A GUI falhou no bot de treinamento e no ruby ​​também. Porém, removi a linha e a adicionei novamente no ponto final (acho que a última foi um erro de copiar e colar).
Steven H.
Em qual sistema operacional você está e quais erros aparecem na linha de comando quando você o executa? Atualmente ele é um bug conhecido que o Windows não pode executar corretamente o sim por causa de argumentos passados através da linha de comando a ser truncado quando excedem o limite de caracteres de linha de comando de cerca de 8000.
Valor de tinta
@ KevinLau-notKenny Estou usando o Windows 10 e recebi ... bem, muitos erros. A primeira coisa foi BeautifulSoup não querer encontrar html5lib, depois não encontrar a pasta que contém todos os bots (eu tive que alterar o código para ambos) e, desde então, a execução de qualquer bot Python resultou em um código de retorno diferente de 0 1.
Steven H.
O Windows ainda não pode executar o código se houver muitas células ativas na tela ... Mas, quanto aos outros erros, pode ser porque o TrainingBot quer o Python 2?
Value Ink
3

Python, GuyWithAGun

Ele é um cara, ele tem uma arma; ele é louco. Ele apenas despeja armas de planador em todos os lugares, sem considerar o que os outros estão fazendo

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)
Azul
fonte
2

Python 3, SquareBot

Coloca quadrados em todos os lugares - talvez

Quadrados são objetos estáticos na Vida - eles não se movem. Portanto, se eu colocar objetos inertes suficientes ao redor do local, os planadores e explosões que outros criam poderão ser bloqueados ou pelo menos umedecidos.

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

Embora eu esteja tendo problemas para testá-lo

Magenta
fonte
Posso confirmar que este bot que de fato fazer o que significou - e ele me ajudou a encontrar e corrigir um erro no controlador
azul