Это жизнь, Джим, но не так, как мы ее знаем

58

Вы, наверное, знаете «Игру жизни» Конвея , знаменитый клеточный автомат, изобретенный математиком Джоном Конвеем. Жизнь - это набор правил, которые вместе позволяют имитировать двумерную доску ячеек. Правила определяют, какие ячейки на доске живут, а какие погибают. С некоторым воображением вы могли бы сказать, что Life - это игра для нулевого игрока: игра, целью которой является поиск моделей с интересным поведением, например, знаменитого планера.

Планер

Игра нулевого игрока ... До сегодняшнего дня. Вы должны написать программу, которая играет в Game of Life - и играет в нее, чтобы победить, в стиле King of the Hill. Ваш оппонент (в единственном числе), конечно, пытается сделать то же самое. Победителем становится либо последний бот с любыми живыми клетками, либо игрок с наибольшим количеством живых клеток после 10000 поколений.

Правила игры

Правила почти такие же, как и у обычных (B3 / S23) Жизнь:

  • Живая клетка с менее чем двумя дружественными соседями умирает от голода.
  • Живая ячейка с двумя или тремя дружелюбными соседями выживает.
  • Живая клетка с более чем тремя дружественными соседями умирает от перенаселения.
  • Мертвая клетка с ровно тремя соседями одного и того же игрока оживает, чтобы сражаться за этого игрока, при условии, что вражеских соседей нет .

... но после каждого поколения и вы, и ваш противник получают возможность вмешаться. Вы можете пробудить до 30 клеток, чтобы сражаться за вас. (Кто идет первым, определяется сервером.)

Доска представляет собой (x, y) квадрат клеток. Все квадраты изначально мертвы. Границы не охватывают (это не мир в форме тора) и навсегда мертвы.

Это соревнование в духе Battlebots и Core Wars . Есть центральный сервер, который будет запускать ботов, и его можно найти здесь

протокол

Сервер арены говорит по простому протоколу JSON, передаваемому через argv

Где Values ​​- строка в кодировке JSON

  • y_size: максимальные координаты y плиток до их исчезновения
  • x_size: максимальные координаты х плиток до их исчезновения
  • tick_id: текущий номер тика
  • board: словарь с ключами в форме '(y, x)' и значениями в форме bot_id(int)
  • bot_id: плитки на доске с этим идентификатором ваши

Пример:

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

Сообщаем серверу ваш выбор:

  • Отправьте серверу список плиток, чтобы они превратились в ваш цвет.
  • Будут изменены только те, которые пусты
  • Формат списка вложенных координат
    • [[0,0], [0,1], [100,22]...]

ПРИМЕЧАНИЕ: ваш бот не должен обновлять плитки вообще - сервер выполняет обновление самостоятельно

Правила соревнований

  • Если ваша реализация не будет следовать протоколу, то ход будет аннулирован; Сервер не примет никаких изменений в состоянии
  • Вам не позволено умышленно воспользоваться ошибкой на сервере арены.
  • Пусть ваш ИИ определится с ходами в разумное время. Пожалуйста, отправьте ваш следующий шаг как можно быстрее.
  • Наконец, пожалуйста, будьте любезны с сервером. Это там для вашего удовольствия.
  • Несоблюдение этих правил может привести к дисквалификации.
  • В случае ничьей обоим игрокам добавляется 1 победа

Запуск контроллера самостоятельно

Источник для контроллера можно найти здесь . Есть 2 способа запуска контроллера:

  • Режим соревнования (терминал)
    • Настройка с python3 get_answers.py
    • Запустите соревнование «все против всех» с каждым ботом, сравнивающим его друг с другом.
  • Режим тестирования (GUI)
    • Бегать python3 nice_gui.py
    • щелчок Pull Answers
    • Если вы хотите добавить свой собственный ответ, чтобы попробовать его перед публикацией, нажмите File -> Add manual answerи найдите файл и выберите язык, на котором он написан.
    • Если ваш язык отсутствует, пингуйте меня, и я попытаюсь установить его на сервере, на котором я буду его запускать (инструкции по установке и запуску тоже подойдут!)
    • Выберите 2 ботов, чтобы противостоять друг другу
    • щелчок Run
    • Смотреть игру ...
  • Монтаж
    • Требуется python3
    • get_answers требует bs4 и html5lib
    • Контроллер требует способ запуска файлов .sh (MinGW на Windows)

Пример изображения приложения

счет

Бот с наибольшим количеством побед, начиная с 12/07/2016(12 июля) 14/07/2016 (14 июля, не смог понять, как запустить бот), побеждает.


Помощь с контроллером / графическим интерфейсом можно попросить в этом чате


Этот вопрос находится в разработке с 2014 года и был самым популярным в песочнице. Особая благодарность выражается Wander Nauta (оригинальный автор и концепция), PPCG Chat (комментарии и помощь) и всем, кто прокомментировал сообщение в песочнице (больше комментариев).

синий
источник
25
Да, я думал, что это никогда не выберется из песочницы. Большой!
Луис Мендо
Опечатка: 12/06/2016 (12 июля)
Луис Мендо
4
+1. Вы заслуживаете награду AED за вынесение этого замечательного вопроса из песочницы!
agtoever
1
@ KevinLau-notKenny о, ладно. Можете ли вы запустить команду в файле?
Rɪᴋᴇʀ
1
@Magenta Когда я их получаю (я совсем забыл об этом, хотя он постоянно открыт), я запускаю его сейчас
Blue

Ответы:

4

Python 3, Exploder

Размещает маленьких взрывников по всему месту, независимо от того, есть ли там уже блок.

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
Я не могу поверить, что после всей моей работы по настройке блоковых переключателей для неограниченного роста и системы, специально созданной для разрушения структур роста, простая система, основанная на взрывах, превзошла мою в бою: o
Value Ink
Я не знаю, как это происходит, потому что я не могу запустить контроллер по любой причине.
Пурпурный
8

Рубин, ПрерывающийБлокМейкер

Вместо инициализации планеров, таких как TrainingBot, он пытается создать машину переключения блоков 5x5, как упоминалось в Википедии, в случайной точке лабиринта. Затем, с оставшимися активациями, он просто находит вражеские точки и пытается засыпать соседние области вашими клетками, пытаясь помешать им расти и, возможно, испортить их паттерны. Ваши клетки умрут в следующем поколении, но, возможно, они также остановили некоторый рост, чтобы замедлить вашего противника!

v2: немного оптимизирован (?), чтобы попытаться минимизировать время ожидания.

v3: Оптимизированный код прерывания для предварительной выборки подмножества активных блоков перед отклонением наших собственных местоположений ячейки, чтобы предотвратить дальнейшие тайм-ауты за счет некоторой эффективности в атаках ячейки прерывания.

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 спасибо, это исправлено! Теперь единственная проблема состоит в том, что команды командной строки Windows имеют жестко заданный предел 8191, что означает, что в определенный момент симуляции боты потерпят крах из-за невозможности анализа усеченной строки JSON. Это проблема ОС, поэтому я думаю, что мне нужно посмотреть на облачный ящик Linux или что-то в этом роде, чтобы протестировать моего бота ~
Value Ink
@muddyfish Я уже упоминал, что у Windows есть проблемы из-за ограничения командной строки, последняя ошибка была на Cloud9, который якобы является Linux-боксом. Как поживает мой бот на вашем Linux-боксе (поскольку вы подразумевали, что он у вас есть)?
Стоимость чернил
Оказывается, я не совершал это, но цифры bot_scoreпоказывают, сколько побед у каждого бота над другими ботами
Blue
Все хорошо, спасибо! К сожалению, Cloud9 действительно не имеет графического интерфейса, и Windows по-прежнему не может запустить симуляцию, не нарушив в конечном итоге свой предел команд, но, по крайней мере, я кратко рассмотрел, как боты живут друг против друга. Кроме того, я иногда вижу, как мой бот борется с самим собой до конца, потому что они продолжают атаковать друг друга и не дают достаточного роста, чтобы преодолеть лимит персонажа, хотя иногда это происходит с таймаутом ...
Value Ink
4

Python 2, TrainingBot

Потому что всем нужен один из них!

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

Ява, Тролль Бот

Бот Тролль подумал об этом, и он понимает, что ему нет дела до врага. На самом деле он просто спамит на этих фабриках, чтобы производить больше своих парней случайным образом по всей карте. Через некоторое время он понял, что любые дополнительные клетки лучше всего использовать в глыбах. Эти блоки из четырех ячеек будут слипаться и останавливают планеры! Он не думает, что он просто борется. Также он большой сторонник подробного объектно-ориентированного программирования. Тролль также предполагает, что координаты имеют формат y, x, и он просит проверить. Просто поместите его в файл с именем "TrollBot.java", и он будет установлен!

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

Этот бот испытывает затруднения при принятии разумных решений, но он, по крайней мере, знает, что не стоит ставить вещи поверх других вещей. Он будет случайным образом создавать планеры, лодки, блоки C / 2 Orthagonal и 2x2 с различной ориентацией, гарантируя, что когда они размещены, они не перекрываются с чем-то еще, союзником или врагом.

Этот бот не был протестирован, поскольку я получаю всевозможные ошибки при попытке запустить графический интерфейс. Кроме того, я использовал TrainingBot в качестве основы и просто редактировал, так что любые сходства в коде, вероятно, из-за этого.

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
GUI, скорее всего, не работает из-за вашей print(sys.argv[1]) в строке 3 испортили вывод (симулятор ожидает только строку координат, которую вы хотите активировать). Кроме того, в последней строке вашей программы отсутствует закрывающая скобка.
Стоимость чернил
@ KevinLau-notKenny Сбой графического интерфейса на тренировочном боте и на Ruby. Я удалил эту строку и добавил обратно в закрывающую часть (я думаю, что последняя была ошибкой копирования-вставки).
Стивен Х.
На какой операционной системе вы работаете и какие ошибки появляются в командной строке при запуске? В настоящее время это известная ошибка, что Windows не может правильно запустить sim из-за того, что аргументы, передаваемые через командную строку, усекаются, когда они превышают ограничение на число символов командной строки около 8000.
Значение Ink
@ KevinLau-notKenny Я использую Windows 10, и я получил ... ну, много ошибок. Первое, что BeautifulSoup не захотел найти html5lib, затем не нашел папку, содержащую все боты (мне пришлось изменить код для обоих), и с тех пор запуск любого бота Python привел к коду возврата, отличному от 0 1.
Стивен Х.
Windows по-прежнему не может запустить код, если на экране слишком много активных ячеек ... Но что касается других ваших ошибок, это может быть из-за того, что TrainingBot хочет Python 2?
Стоимость чернил
3

Python, GuyWithAGun

Он парень, у него есть пистолет; он безумен Он просто сбрасывает планерные пушки везде, не обращая внимания на то, что делает кто-то еще

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

Размещает квадраты везде, может быть

Квадраты - это статичные объекты в жизни - они не двигаются. Поэтому, если я размещу достаточно инертных объектов вокруг этого места, планеры и взрывы, которые создают другие, возможно, будут заблокированы или, по крайней мере, ослаблены.

-Принято из 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)

Хотя у меня проблемы с его тестированием

фуксин
источник
Я могу подтвердить, что этот бот действительно делает то, для чего предназначен - и это помогло мне найти и исправить ошибку в контроллере
Blue