It's Life, Jim, but not as we know it

59

10

You probably know Conway's Game of Life, the famous cellular automaton invented by mathematician John Conway. Life is a set of rules that, together, allow you to simulate a two-dimensional board of cells. The rules decide which cells on the board live and which ones die. With some imagination, you could say that Life is a zero-player game: a game with the objective to find patterns with interesting behavior, like the famous glider.

Glider

A zero-player game... Until today. You are to write a program that plays the Game of Life - and plays it to win, King of the Hill-style. Your opponent (singular) of course tries to do the same. The winner is either the last bot with any live cells, or the player with the most live cells after 10000 generations.

Game rules

The rules are almost the same as normal (B3/S23) Life:

  • A live cell with fewer than two friendly neighbors dies from starvation.
  • A live cell with two or three friendly neighbors survives.
  • A live cell with more than three friendly neighbors dies from overpopulation.
  • A dead cell with exactly three neighbors of the same player comes alive to fight for that player provided there are no enemy neighbors.

...but after each generation, both you and your opponent get the opportunity to intervene. You can awake up to a maximum of 30 cells to fight for you. (Who goes first is decided by the server.)

The board is a (x,y) cells square. All squares are initially dead. The borders do not wrap around (this is not a torus-shaped world) and are permanently dead.

This is is a contest in the spirit of Battlebots and Core Wars. There is a central server that will run bots and it can be found here

Protocol

The arena server speaks a simple JSON protocol communicated through argv

Where Values is a JSON encoded string

  • y_size: the maximum y coords of tiles before they vanish
  • x_size: the maximum x coords of tiles before they vanish
  • tick_id: the current tick number
  • board: a dictionary with keys in the form '(y,x)' and values in the form bot_id (int)
  • bot_id: tiles in the board with this id are yours

Example:

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

Telling the server your choice:

  • Send the server a list of tiles to turn to your colour.
  • Only those that are empty will be changed
  • Nested coords list format
    • [[0,0], [0,1], [100,22]...]

NOTE: Your bot doesn't have to update the tiles at all - the server does the updating itself

Competition rules

  • If your implementation fails to follow the protocol, the turn it does will be forfeited; The server will assume no change in state
  • You are not allowed to willfully take advantage of a fault in the arena server.
  • Have your AI decide on moves in a sane time. Please send your next move as fast as reasonably possible.
  • Finally, please be nice to the server. It's there for your enjoyment.
  • Not following these rules can lead to disqualification.
  • In the event of a tie, both players have 1 win added to their total

Running the controller yourself

The source for the controller can be found here. There are 2 ways of running the controller:

  • Competition mode (terminal)
    • Setup with python3 get_answers.py
    • Run an all v all competition with each bot pitting it against every other.
  • Testing mode (GUI)
    • Run python3 nice_gui.py
    • Click Pull Answers
    • If you want to add your own answer to try it before posting, click File -> Add manual answer and find the file and choose the language it's written in.
    • If your language isn't present ping me and I'll try to get it installed on the server I will run it on (installation and running instructions would be nice too!)
    • Choose 2 bots to pit against each other
    • Click Run
    • Watch the game...
  • Installation
    • Requires python3
    • get_answers requires bs4 and html5lib
    • controller requires a way of running .sh files (MinGW on windows)

Example image of app

Scoring

The bot with the most wins starting from 12/07/2016 (12th July) 14/07/2016 (14th July, couldn't work out how to run a bot) wins.


Help with the controller/gui can be asked in this chat room


This question has been in development since 2014 and was the most upvoted question in the sandbox. Special Thanks goes to Wander Nauta (original author and concept), PPCG Chat (comments and help) and anyone who commented in the sandbox post (more comments).

Blue

Posted 2016-06-28T21:21:17.973

Reputation: 26 661

25Huh, I thought this would never make it out of the sandbox. Great! – Luis Mendo – 2016-06-28T21:23:37.173

Typo: 12/06/2016 (12th July) – Luis Mendo – 2016-06-28T21:32:48.933

so you didn't use my server? – TheDoctor – 2016-06-28T21:34:40.227

@muddyfish sorry- this seems like tech support, but the gui is blank, and the get_answers does not return anything for me. – Magenta – 2016-07-01T10:24:39.113

Is the bot id garunteed to be a single character? – Rohan Jhunjhunwala – 2016-07-01T14:36:47.817

@RohanJhunjhunwala the bot id will be either 1 or 2 – Blue – 2016-07-01T16:40:56.190

@Magenta Did you press the pull answers button in the gui and click yes? That should fill it with answers – Blue – 2016-07-01T16:42:16.760

There is a bug where bots timing out (my Ruby bot was timing out a lot) cause crashes in the server code. I've sent a pull request to fix it.

– Value Ink – 2016-07-01T19:51:18.340

@muddyfish when i pull answers, that works, and the different bots can be selected. However, the rest of the gui is blank. – Magenta – 2016-07-01T20:02:14.500

You need to click run? Try moving the window about if that doesn't work, if stuff starts miraculously appearing I have no idea how to fix it – Blue – 2016-07-01T21:03:04.613

What is the exact format of the "dictionary" in the board – Rohan Jhunjhunwala – 2016-07-02T14:52:21.520

Is it {'(y1,x1)',id1,'(y2,x2)',id2,(y3,x3),id3} etc... – Rohan Jhunjhunwala – 2016-07-02T14:54:09.077

If my bot tries to activate more than 30 cells what happens? – Rohan Jhunjhunwala – 2016-07-02T14:54:27.030

Are additional cells ignored or do i lose a turn? – Rohan Jhunjhunwala – 2016-07-02T14:54:54.970

4+1. You deserve the AED award for bringing this great question out of the sandbox! – agtoever – 2016-07-03T18:59:40.827

@RohanJhunjhunwala the dictionary format can be found in the chat link in the question, additional cells get filtered out. agtoever Thanks! – Blue – 2016-07-03T19:21:48.490

Sorry I am so needy, but if someone would like to take a look at the "Troll Bot", and run it. I would like to see it tested so I can optimize it. The client arena wont work as I'm on a windows machine and the hardcoded command limit will prevent me from seeing the whole game. If anyone would let me know if it worked for them. That would be great! – Rohan Jhunjhunwala – 2016-07-04T01:14:17.660

@RohanJhunjhunwala why won't it work on windows? – Rɪᴋᴇʀ – 2016-07-05T23:50:34.790

@EᴀsᴛᴇʀʟʏIʀᴋ Windows commandline commands have a hardcoded limit of 8191 (to my knowledge, there might be a shell that beats the limit). The input to these programs is a command line argument, and considering the 1000x1000 board the input passed in (which is formatted to list every single active cell) can easily fly past that limit – Value Ink – 2016-07-06T01:04:55.250

1@KevinLau-notKenny oh, okay. Can you run a command in a file? – Rɪᴋᴇʀ – 2016-07-06T01:16:40.953

If I try to activate a cell thats already activated is that ignored? – Rohan Jhunjhunwala – 2016-07-07T01:15:23.710

Rohan, yes. It still counts as one of the 30 though – Blue – 2016-07-07T05:33:03.627

@muddyfish if you are having trouble running all the bots together you could probably get a cloud9 partition and run it from there? I'm just sad that my bot is the only one that uses a strategy based on the opponent's board state instead of dropping things wherever

– Value Ink – 2016-07-12T20:52:14.637

The problem's been fixed, just testing now. – Blue – 2016-07-12T21:02:21.643

It's a real shame that there weren't too many bots for this one... I feel like the Windows problem was a big issue, but there's nothing that can be done about that now – Value Ink – 2016-07-19T00:38:34.673

@muddyfish You should select mark the winning bot as accepted and post the scores if the competition is indeed over as of July 14th. – mbomb007 – 2016-07-22T18:45:28.543

I'm not accepting yet because I'm waiting on trollbot. I still can't run it – Blue – 2016-07-22T18:48:27.880

@muddyfish When are the scores going to be up? – Magenta – 2016-08-20T06:18:37.613

1@Magenta When I get them (I'd completely forgotten about this even though it's been in a constantly open tab), I'm running it now – Blue – 2016-08-20T10:00:37.960

Answers

5

Python 3, Exploder

Puts small exploders around the place, with no regard to whether there is already a block there.

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

Posted 2016-06-28T21:21:17.973

Reputation: 1 322

1I can't believe that after all my work setting up block-making switches for indefinite growth and a system specifically built to demolish growth structures, a simple exploder-based system bested mine in combat :o – Value Ink – 2017-03-07T22:40:00.217

I don't know how it does either, because I can't run the controller for whatever reason. – Magenta – 2017-03-08T07:50:47.747

8

Ruby, InterruptingBlockMaker

Instead of initializing gliders like the TrainingBot, it tries to create a 5x5 block-making switch machine as mentioned on Wikipedia at a random point in the maze. Then, with its remaining activations, it just finds enemy points and tries to pepper the nearby area with your cells in an attempt to interrupt them from growing and possibly messing up their patterns. Your cells will die in the next generation, but maybe they also stopped some growth to slow down your opponent!

v2: Optimized slightly (?) to try to minimize timeouts.

v3: Optimized interruption code to pre-sample a subset of active blocks before rejecting our own cell locations, to prevent timeouts further at the cost of some effectiveness in the interrupt cell attacks.

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

Posted 2016-06-28T21:21:17.973

Reputation: 10 608

@muddyfish thanks, that fixed it! Now the only issue is that Windows command line commands have a hardcoded limit of 8191, which means that at a certain point in the simulation the bots will crash from being unable to parse the truncated JSON string. It's an OS issue, so I guess I have have to look into a Linux cloud box or something in order to test my bot~ – Value Ink – 2016-06-29T21:09:28.793

@muddyfish I already mentioned that Windows has problems because of the command line limit, that last error was on Cloud9 which is ostensibly a Linux box. How does my bot fare on your Linux box (since you implied that you had one)? – Value Ink – 2016-06-29T22:45:52.920

Turns out I hadn't committed it but the numbers in bot_score show how many wins each bot has against other bots – Blue – 2016-06-30T21:11:00.847

All right, thanks! Unfortunately, Cloud9 indeed does not have a GUI and Windows still can't run the simulation without breaking its command limit eventually, but at least I got a brief look into how the bots fare against each other. Also, I get to see my bot fight against itself to the end some times because they keep attacking each other and preventing enough growth to break the character limit, although it does time out occasionally... – Value Ink – 2016-06-30T21:33:49.110

4

Python 2, TrainingBot

Because everyone needs one of these!

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)

Blue

Posted 2016-06-28T21:21:17.973

Reputation: 26 661

4

Java, Troll Bot

Troll Bot has thought about it, and he realizes he does NOT care about the enemy. In fact he just spams these factories to produce more of his guys randomly all over the map. After a while he realized that any additional cells are best used in clumps. These blocks of four cells will stick together and stop gliders in their tracks! He does not think he just fights. Also he is a big supporter of verbose object oriented programming. The troll also assumes that coords are in the format y,x, and he is asking to be tested. Just put him in a file called "TrollBot.java", and he'll be set!

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

Posted 2016-06-28T21:21:17.973

Reputation: 2 569

3

Python 3, RandomBot

This bot has trouble making intelligent decisions, but it at least knows not to try to place things on top of other things. It'll randomly create gliders, boats, C/2 Orthagonals, and 2x2 blocks with various orientations, ensuring that when they're placed they're not overlapping with something else, ally or enemy.

This bot wasn't tested, seeing as I'm receiving all sorts of errors when I try to run the GUI. Also, I used the TrainingBot as the base and just edit, so any similarities in code is probably because of that.

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.

Posted 2016-06-28T21:21:17.973

Reputation: 2 841

1The GUI is most likely failing because of your print(sys.argv[1]) on line 3, which messes up the output (the simulator expects only the string of coordinates you want to wake up). Also, the last line of your program is missing a closing paren. – Value Ink – 2016-06-30T22:56:56.980

@KevinLau-notKenny The GUI was failing on the training bot and the Ruby bot as well. I removed that line, though, and added back in the closing paren (I think that latter one was a copy-paste error). – Steven H. – 2016-06-30T23:04:03.783

What operating system are you on, and what errors appear in the command line when you run it? Currently it's a known bug that Windows cannot properly run the sim because of arguments passed through command line being truncated when they exceed the command line character limit of around 8000. – Value Ink – 2016-06-30T23:21:16.180

@KevinLau-notKenny I'm using Windows 10, and I've gotten... well, a lot of errors. The first thing was BeautifulSoup not wanting to find html5lib, then not finding the folder containing all the bots (I had to change the code for both of these), and since then the running of either Python bot has resulted in a non-0 return code 1. – Steven H. – 2016-06-30T23:24:56.933

Windows still can't run the code if there are too many active cells on the screen... But as for your other errors, it might be because TrainingBot wants Python 2? – Value Ink – 2016-06-30T23:27:28.287

@KevinLau-notKenny Might be it. I'll try it with your bot and see if that helps things at all. – Steven H. – 2016-06-30T23:33:16.283

Let us continue this discussion in chat.

– Steven H. – 2016-06-30T23:40:37.680

3

Python, GuyWithAGun

He's a guy, he's got a gun; he's mad. He just dumps glider guns everywhere with no regard to what anyone else is doing

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)

Blue

Posted 2016-06-28T21:21:17.973

Reputation: 26 661

2

Python 3, SquareBot

Puts squares everywhere- maybe

Squares are static objects in Life- they do not move. So if I place enough inert objects around the place, the gliders and explosions that others create will possibly be blocked, or at least dampened.

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

Although I am having trouble testing it

Magenta

Posted 2016-06-28T21:21:17.973

Reputation: 1 322

I can confirm that this bot does in fact do what it's meant to - and it helped me find and fix a bug in the controller – Blue – 2016-07-01T21:12:08.307