Es la vida, Jim, pero no como la conocemos.


58

Probablemente conozcas Conway's Game of Life , el famoso autómata celular inventado por el matemático John Conway. La vida es un conjunto de reglas que, juntas, le permiten simular un tablero de celdas bidimensional. Las reglas deciden qué células en el tablero viven y cuáles mueren. Con un poco de imaginación, se podría decir que la vida es un juego de cero jugadores: un juego con el objetivo de encontrar patrones con un comportamiento interesante, como el famoso planeador.

Planeador

Un juego de cero jugadores ... Hasta hoy. Debes escribir un programa que juegue el Juego de la Vida, y lo juegue para ganar, al estilo King of the Hill. Tu oponente (singular), por supuesto, intenta hacer lo mismo. El ganador es el último bot con células vivas o el jugador con más células vivas después de 10000 generaciones.

Reglas del juego

Las reglas son casi las mismas que la vida normal (B3 / S23):

  • Una célula viva con menos de dos vecinos amigos muere de hambre.
  • Sobrevive una celda viva con dos o tres vecinos amigos.
  • Una célula viva con más de tres vecinos amigos muere por sobrepoblación.
  • Una celda muerta con exactamente tres vecinos del mismo jugador cobra vida para luchar por ese jugador siempre que no haya vecinos enemigos .

... pero después de cada generación, tanto tú como tu oponente tienen la oportunidad de intervenir. Puedes despertar hasta un máximo de 30 células para luchar por ti. (El servidor decide quién va primero).

El tablero es un cuadrado de celdas (x, y). Todos los cuadrados están inicialmente muertos. Las fronteras no se envuelven (este no es un mundo en forma de toro) y están permanentemente muertas.

Este es un concurso en el espíritu de Battlebots y Core Wars . Hay un servidor central que ejecutará bots y se puede encontrar aquí

Protocolo

El servidor de arena habla un protocolo JSON simple comunicado a través de argv

Donde valores es una cadena codificada JSON

  • y_size: el máximo y coords de azulejos antes de que desaparezcan
  • x_size: el máximo x coords de fichas antes de que desaparezcan
  • tick_id: el número de marca actual
  • board: un diccionario con claves en la forma '(y, x)' y valores en la forma bot_id(int)
  • bot_id: las fichas en el tablero con esta identificación son tuyas

Ejemplo:

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

Diciéndole al servidor su elección:

  • Envíe al servidor una lista de mosaicos para cambiar a su color.
  • Solo aquellos que estén vacíos serán cambiados
  • Formato de lista de coordenadas anidadas
    • [[0,0], [0,1], [100,22]...]

NOTA: su bot no tiene que actualizar los mosaicos en absoluto: el servidor realiza la actualización por sí mismo

Normas de competencia

  • Si su implementación no sigue el protocolo, se perderá el turno; El servidor asumirá que no hay cambios en el estado.
  • No está permitido aprovechar deliberadamente una falla en el servidor de arena.
  • Haz que tu IA decida sobre movimientos en un tiempo razonable. Envíe su próximo movimiento lo más rápido posible.
  • Finalmente, por favor sea amable con el servidor. Está ahí para su disfrute.
  • No seguir estas reglas puede conducir a la descalificación.
  • En caso de empate, ambos jugadores tienen 1 victoria añadida a su total.

Ejecutando el controlador usted mismo

La fuente del controlador se puede encontrar aquí . Hay 2 formas de ejecutar el controlador:

  • Modo de competencia (terminal)
    • Configurar con python3 get_answers.py
    • Realiza una competencia all v all con cada bot enfrentándolo entre sí.
  • Modo de prueba (GUI)
    • correr python3 nice_gui.py
    • Hacer clic Pull Answers
    • Si desea agregar su propia respuesta para probarlo antes de publicar, haga clic File -> Add manual answery busque el archivo y elija el idioma en el que está escrito.
    • Si su idioma no está presente, hágame ping e intentaré instalarlo en el servidor en el que lo ejecutaré (¡las instrucciones de instalación y ejecución también serían buenas!)
    • Elige 2 bots para enfrentarse entre sí
    • Hacer clic Run
    • Mira el juego...
  • Instalación
    • Requiere python3
    • get_answers requiere bs4 y html5lib
    • el controlador requiere una forma de ejecutar archivos .sh (MinGW en Windows)

Imagen de ejemplo de la aplicación

Puntuación

El bot con la mayor cantidad de victorias a partir del 12/07/2016(12 de julio) 14/07/2016 (14 de julio, no pudo resolver cómo ejecutar un bot) gana.


Puede solicitar ayuda con el controlador / gui en esta sala de chat


Esta pregunta ha estado en desarrollo desde 2014 y fue la pregunta más votada en el sandbox. Un agradecimiento especial a Wander Nauta (autor original y concepto), PPCG Chat (comentarios y ayuda) y cualquiera que haya comentado en la publicación de sandbox (más comentarios).


25
Huh, pensé que esto nunca saldría de la caja de arena. ¡Excelente!
Luis Mendo

Error tipográfico: 06/12/2016 (12 de julio)
Luis Mendo

44
+1. ¡Te mereces el premio AED por sacar esta gran pregunta de la caja de arena!
agtoever

1
@ KevinLau-notKenny oh, está bien. ¿Se puede ejecutar un comando en un archivo?
Rɪᴋᴇʀ

1
@Magenta Cuando los obtengo (me había olvidado por completo de esto a pesar de que estaba en una pestaña constantemente abierta), lo estoy ejecutando ahora
azul

Respuestas:


4

Python 3, Exploder

Coloca pequeños explosores alrededor del lugar, sin importar si ya hay un bloque allí.

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)

1
No puedo creer que después de todo mi trabajo estableciendo interruptores de fabricación de bloques para un crecimiento indefinido y un sistema específicamente diseñado para demoler estructuras de crecimiento, un sistema simple basado en explosivos superó a la mía en combate: o
Value Ink

Tampoco sé cómo funciona, porque no puedo ejecutar el controlador por cualquier razón.
Magenta

8

Ruby, interruptingBlockMaker

En lugar de inicializar planeadores como el TrainingBot, intenta crear una máquina de interruptores de creación de bloques de 5x5 como se menciona en Wikipedia en un punto aleatorio en el laberinto. Luego, con sus activaciones restantes, solo encuentra puntos enemigos y trata de acribillar el área cercana con sus células en un intento de interrumpir su crecimiento y posiblemente estropear sus patrones. ¡Tus células morirán en la próxima generación, pero tal vez también detuvieron algo de crecimiento para ralentizar a tu oponente!

v2: Optimizado ligeramente (?) para intentar minimizar los tiempos de espera.

v3: Código de interrupción optimizado para muestrear previamente un subconjunto de bloques activos antes de rechazar nuestras propias ubicaciones de celdas, para evitar tiempos de espera adicionales a costa de cierta efectividad en los ataques de celdas de interrupción.

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)

@muddyfish gracias, eso lo solucionó! Ahora, el único problema es que los comandos de la línea de comandos de Windows tienen un límite codificado de 8191, lo que significa que en cierto punto de la simulación los bots se bloquearán por no poder analizar la cadena JSON truncada. Es un problema del sistema operativo, así que supongo que tengo que buscar en una caja de nube de Linux o algo así para probar mi bot ~
Value Ink

@muddyfish Ya mencioné que Windows tiene problemas debido al límite de la línea de comandos, ese último error fue en Cloud9, que aparentemente es un cuadro de Linux. ¿Cómo le va a mi bot en su caja de Linux (ya que usted dio a entender que tenía uno)?
Value Ink

Resulta que no lo había cometido, pero los números bot_scoremuestran cuántas victorias tiene cada bot contra otros bots
azul

¡Muy bien, gracias! Desafortunadamente, Cloud9 de hecho no tiene una GUI y Windows todavía no puede ejecutar la simulación sin romper su límite de comando eventualmente, pero al menos tuve una breve mirada sobre cómo los robots se enfrentan entre sí. Además, algunas veces veo que mi robot lucha contra sí mismo hasta el final porque se siguen atacando entre sí y evitan el crecimiento suficiente para romper el límite de caracteres, aunque ocasionalmente se agota el tiempo ...
Value Ink

4

Python 2, TrainingBot

¡Porque todos necesitan uno de estos!

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)

4

Java, Troll Bot

Troll Bot lo ha pensado y se da cuenta de que NO le importa el enemigo. De hecho, simplemente envía mensajes a estas fábricas para producir más de sus muchachos al azar en todo el mapa. Después de un tiempo se dio cuenta de que cualquier celda adicional se usa mejor en grupos. ¡Estos bloques de cuatro celdas se unirán y detendrán a los planeadores en su camino! No cree que solo pelea. También es un gran defensor de la programación orientada a objetos detallada. El troll también asume que las coordenadas están en el formato y, x, y está pidiendo que lo prueben. Simplemente póngalo en un archivo llamado "TrollBot.java", ¡y estará listo!

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
    }

}

3

Python 3, RandomBot

Este bot tiene problemas para tomar decisiones inteligentes, pero al menos sabe que no debe tratar de colocar las cosas por encima de otras. Al azar creará planeadores, botes, C / 2 Orthagonal s y bloques de 2x2 con varias orientaciones, asegurando que cuando se colocan no se superpongan con otra cosa, aliado o enemigo.

Este bot no se probó, ya que recibo todo tipo de errores cuando intento ejecutar la GUI. Además, utilicé TrainingBot como base y simplemente edité, por lo que cualquier similitud en el código probablemente se deba a eso.

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

1
Lo más probable es que la GUI esté fallando debido a su print(sys.argv[1])línea 3, que desordena la salida (el simulador solo espera la cadena de coordenadas que desea despertar). Además, a la última línea de su programa le falta un par de cierre.
Value Ink

@ KevinLau-notKenny La GUI estaba fallando en el robot de entrenamiento y el robot Ruby también. Sin embargo, eliminé esa línea y agregué nuevamente en el par de cierre (creo que este último fue un error de copiar y pegar).
Steven H.

¿En qué sistema operativo estás y qué errores aparecen en la línea de comando cuando lo ejecutas? Actualmente es un error conocido que Windows no puede ejecutar correctamente el sim debido a que los argumentos pasados ​​a través de la línea de comando se truncan cuando exceden el límite de caracteres de la línea de comando de alrededor de 8000.
Value Ink

@ KevinLau-notKenny Estoy usando Windows 10, y he recibido ... bueno, muchos errores. Lo primero fue que BeautifulSoup no quería encontrar html5lib, luego no encontró la carpeta que contenía todos los bots (tuve que cambiar el código para ambos), y desde entonces la ejecución de cualquiera de los bots de Python ha resultado en un código de retorno distinto de 0 1.
Steven H.

Windows todavía no puede ejecutar el código si hay demasiadas celdas activas en la pantalla ... Pero en cuanto a sus otros errores, ¿podría ser porque TrainingBot quiere Python 2?
Value Ink

3

Python, GuyWithAGun

Es un chico, tiene una pistola; él está loco. Simplemente arroja pistolas planeadoras en todas partes sin tener en cuenta lo que alguien más está haciendo

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)

2

Python 3, SquareBot

Pone cuadrados en todas partes, tal vez

Los cuadrados son objetos estáticos en la vida, no se mueven. Entonces, si coloco suficientes objetos inertes alrededor del lugar, los planeadores y las explosiones que otros crean posiblemente se bloquearán, o al menos se humedecerán.

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

Aunque tengo problemas para probarlo



Puedo confirmar que este bot de hecho hace lo que debe hacer, y me ayudó a encontrar y corregir un error en el controlador
azul el
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.