C'est la vie, Jim, mais pas tel que nous le connaissons

58

Vous connaissez probablement le Game of Life de Conway , le célèbre automate cellulaire inventé par le mathématicien John Conway. La vie est un ensemble de règles qui, ensemble, vous permettent de simuler un tableau de cellules en deux dimensions. Les règles déterminent quelles cellules du tableau vivent et lesquelles meurent. Avec un peu d'imagination, on pourrait dire que Life est un jeu à joueur nul: un jeu dont l'objectif est de trouver des modèles de comportement intéressant, comme le célèbre planeur.

Planeur

Un jeu à zéro joueur ... Jusqu'à aujourd'hui. Vous devez écrire un programme qui joue le jeu de la vie - et le joue pour gagner, à la manière du roi de la colline. Votre adversaire (singulier) essaie bien sûr de faire de même. Le gagnant est soit le dernier bot avec une cellule vivante, soit le joueur avec le plus de cellules vivantes après 10000 générations.

Regles du jeu

Les règles sont presque les mêmes que pour la vie normale (B3 / S23):

  • Une cellule vivante avec moins de deux voisins amis meurt de faim.
  • Une cellule vivante avec deux ou trois voisins amicaux survit.
  • Une cellule vivante avec plus de trois voisins amis décède de la surpopulation.
  • Une cellule morte avec exactement trois voisins du même joueur s'anime pour se battre pour ce joueur s'il n'y a pas de voisins ennemis .

... mais après chaque génération, vous et votre adversaire avez la possibilité d'intervenir. Vous pouvez vous réveiller avec un maximum de 30 cellules pour vous battre. (Qui va en premier est décidé par le serveur.)

Le tableau est un carré (x, y) de cellules. Toutes les places sont initialement mortes. Les frontières ne s’enroulent pas (ce n’est pas un monde en forme de tore) et sont définitivement mortes.

Ceci est un concours dans l'esprit de Battlebots et Core Wars . Il y a un serveur central qui exécutera des bots et on peut le trouver ici

Protocole

Le serveur d'arène parle un protocole JSON simple communiqué via argv

Où Values ​​est une chaîne encodée JSON

  • y_size: le nombre maximal de carreaux avant leur disparition
  • x_size: le nombre maximum de coords de carreaux avant qu'ils ne disparaissent
  • tick_id: le numéro de tick actuel
  • board: un dictionnaire avec des clés sous la forme '(y, x)' et des valeurs sous la forme bot_id(int)
  • bot_id: les tuiles dans le tableau avec cet identifiant sont à vous

Exemple:

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

Dire au serveur votre choix:

  • Envoyez au serveur une liste de tuiles pour qu’elles adoptent votre couleur.
  • Seuls ceux qui sont vides seront changés
  • Format de liste de coordonnées imbriquées
    • [[0,0], [0,1], [100,22]...]

NOTE: Votre bot n'a pas du tout besoin de mettre à jour les tuiles - le serveur se met à jour lui-même

Règlement du concours

  • Si votre implémentation ne respecte pas le protocole, son tour sera perdu; Le serveur n'assume aucun changement d'état
  • Vous n'êtes pas autorisé à tirer volontairement parti d'une défaillance du serveur d'arène.
  • Demandez à votre IA de décider de se déplacer dans un moment sain. S'il vous plaît envoyer votre prochain déménagement aussi rapidement que raisonnablement possible.
  • Enfin, s'il vous plaît soyez gentil avec le serveur. C'est là pour votre plaisir.
  • Ne pas suivre ces règles peut entraîner une disqualification.
  • En cas d'égalité, les deux joueurs ont 1 victoire ajoutée à leur total

Faire fonctionner le contrôleur vous-même

La source du contrôleur peut être trouvée ici . Il y a 2 manières de faire fonctionner le contrôleur:

  • Mode compétition (terminal)
    • Mis en place avec python3 get_answers.py
    • Lancez une compétition tous contre tous avec chaque bot en le confrontant les uns avec les autres.
  • Mode de test (GUI)
    • Courir python3 nice_gui.py
    • Cliquez sur Pull Answers
    • Si vous souhaitez ajouter votre propre réponse avant de la publier, cliquez dessus File -> Add manual answer, recherchez le fichier et choisissez la langue dans laquelle il est écrit.
    • Si votre langue n'est pas présente, envoyez-moi une requête ping et essayez de l'installer sur le serveur. Je l'exécuterai (les instructions d'installation et d'exécution seraient également utiles!)
    • Choisissez 2 robots pour vous opposer
    • Cliquez sur Run
    • Regarde le jeu...
  • Installation
    • Requiert python3
    • get_answers requiert bs4 et html5lib
    • Le contrôleur requiert un moyen d’exécuter des fichiers .sh (MinGW sur Windows)

Exemple d'image de l'application

Notation

Le bot avec le plus grand nombre de victoires à partir du 12/07/201612 juillet 14/07/2016 (le 14 juillet, ne sait pas comment gérer un bot) gagne.


Vous pouvez demander de l'aide avec le contrôleur / interface graphique dans cette salle de discussion.


Cette question est en développement depuis 2014 et était la question la plus votée dans le bac à sable. Un merci tout spécial à Wander Nauta (auteur et concept original), au chat PPCG (commentaires et aide) et à tous ceux qui ont fait des commentaires dans le post Sandbox (plus de commentaires).

Bleu
la source
25
Euh, j'ai pensé que cela ne sortirait jamais du bac à sable. Génial!
Luis Mendo
Typo: 12/06/2016 (12 juillet)
Luis Mendo le
4
+1 Vous méritez le prix AED pour avoir soulevé cette grande question du bac à sable!
agtoever
1
@ KevinLau-notKenny oh, d'accord. Pouvez-vous exécuter une commande dans un fichier?
Rɪᴋᴇʀ
1
@Magenta Quand je les ai (je l'avais complètement oubliée même si ça a été dans un onglet ouvert en permanence), je le cours maintenant
Bleu

Réponses:

4

Python 3, Exploder

Met de petits exploseurs autour de la place, sans se soucier de savoir s'il y a déjà un bloc là-bas.

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
la source
1
Je n'arrive pas à croire qu'après tout mon travail de mise en place de commutateurs pour la croissance indéfinie et un système spécialement conçu pour démolir les structures de croissance, un système simple à base d'exploseur a vaincu le mien au combat: o
Value Ink
Je ne sais pas non plus comment cela fonctionne, car je ne peux pas exécuter le contrôleur pour une raison quelconque.
Magenta
8

Ruby, InterruptingBlockMaker

Au lieu d'initialiser des planeurs comme le TrainingBot, il tente de créer une machine de commutation de blocs 5x5, comme mentionné sur Wikipedia, à un point aléatoire du labyrinthe. Ensuite, avec les activations restantes, il ne fait que trouver des points ennemis et tente de recouvrir vos cellules de la zone voisine afin de les empêcher de se développer et de gâcher leurs schémas. Vos cellules mourront à la prochaine génération, mais peut-être ont-elles également cessé de croître pour ralentir votre adversaire!

v2: légèrement optimisé (?) pour essayer de minimiser les délais.

v3: Code d'interruption optimisé pour pré-échantillonner un sous-ensemble de blocs actifs avant de rejeter nos propres emplacements de cellule, afin d'éviter des délais d'attente plus longs au détriment de l'efficacité des attaques de cellules d'interruption.

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)
Valeur d'encre
la source
@muddyfish merci, ça a réglé le problème! Le seul problème est que les commandes de ligne de commande Windows ont une limite codée en dur de 8191, ce qui signifie qu'à un moment donné de la simulation, les bots ne pourront plus analyser la chaîne JSON tronquée. C'est un problème de système d'exploitation, donc je suppose que je dois regarder dans une boîte de nuage Linux ou quelque chose afin de tester mon bot ~
Value Ink
@muddyfish J'ai déjà mentionné que Windows avait des problèmes en raison de la limite de ligne de commande, cette dernière erreur était sur Cloud9 qui est apparemment une machine Linux. Comment se comporte mon bot sur votre machine Linux (puisque vous avez laissé entendre que vous en aviez un)?
Valeur d'encre
Il s'avère que je ne l'avais pas commis, mais les chiffres indiqués bot_scoreindiquent le nombre de victoires de chaque bot sur d'autres bots
Bleu
D'accord, merci! Malheureusement, Cloud9 n’a effectivement pas d’interface graphique et Windows ne peut toujours pas exécuter la simulation sans dépasser sa limite de commande, mais au moins j’ai eu un bref aperçu de la façon dont les bots se font face. De plus, je vois parfois mon bot se battre jusqu'à la fin parce qu'il s'attaque constamment et empêche suffisamment de croissance pour dépasser la limite du nombre de personnages, bien qu'il arrive parfois à expiration ...
Value Ink le
4

Python 2, TrainingBot

Parce que tout le monde en a besoin!

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)
Bleu
la source
4

Java, troll bot

Troll Bot y a réfléchi et se rend compte qu'il ne s'intéresse pas à l'ennemi. En fait, il demande à ces usines de produire davantage de ses gars au hasard sur la carte. Après un moment, il se rendit compte que les cellules supplémentaires sont mieux utilisées dans les touffes. Ces blocs de quatre cellules vont rester ensemble et arrêter les planeurs dans leurs traces! Il ne pense pas qu'il se bat juste. En outre, il est un grand partisan de la programmation orientée objet verbeuse. Le troll suppose également que les coordonnées sont au format y, x, et il demande à être testé. Il suffit de le placer dans un fichier appelé "TrollBot.java" et il sera configuré!

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
la source
3

Python 3, RandomBot

Ce bot a du mal à prendre des décisions intelligentes, mais il sait au moins ne pas essayer de placer les choses au-dessus d’autres choses. Il créera au hasard des planeurs, des bateaux, des blocs C / 2 Orthagonal et des blocs 2x2 avec des orientations variées, afin de garantir qu’ils ne se chevauchent pas avec quelque chose d’autre, allié ou ennemi.

Ce bot n'a pas été testé, vu que je reçois toutes sortes d'erreurs lorsque j'essaie d'exécuter l'interface graphique. De plus, j'ai utilisé TrainingBot comme base et juste pour éditer, donc toute similitude de code est probablement due à cela.

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.
la source
1
L’interface graphique échoue probablement à cause de votre print(sys.argv[1])ligne 3, qui gâche la sortie (le simulateur attend uniquement la chaîne de coordonnées que vous voulez réactiver). De plus, il manque un paren de clôture à la dernière ligne de votre programme.
Valeur d'encre
@ KevinLau-notKenny L'interface graphique échouait également sur le bot d'entraînement et le bot Ruby. J'ai supprimé cette ligne, cependant, et rajouté dans le paren de clôture (je pense que ce dernier était une erreur de copier-coller).
Steven H.
Sur quel système d'exploitation utilisez-vous et quelles erreurs apparaissent dans la ligne de commande lorsque vous l'exécutez? Actuellement, il est connu que Windows ne peut pas exécuter correctement la simulation à cause d'arguments tronqués tronqués lorsqu'ils dépassent la limite de caractères de la ligne de commande d'environ 8 000.
Valeur Ink
@ KevinLau-notKenny J'utilise Windows 10 et j'ai eu ... eh bien, beaucoup d'erreurs. La première chose était BeautifulSoup ne voulant pas trouver html5lib, puis ne trouvant pas le dossier contenant tous les robots (je devais changer le code pour les deux), et depuis lors, le fonctionnement de l'un des deux robots Python a entraîné un code de retour non nul. 1.
Steven H.
Windows ne peut toujours pas exécuter le code s'il y a trop de cellules actives à l'écran ... Mais pour vos autres erreurs, c'est peut-être parce que TrainingBot veut Python 2?
Valeur d'encre
3

Python, GuyWithAGun

C'est un gars, il a une arme à feu; il est fou. Il se débarrasse des armes à feu de planeur partout sans se soucier de ce que font les autres

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)
Bleu
la source
2

Python 3, SquareBot

Place des carrés partout - peut-être

Les carrés sont des objets statiques dans la vie, ils ne bougent pas. Donc, si je place suffisamment d'objets inertes autour de la place, les planeurs et les explosions que d'autres créent peuvent éventuellement être bloqués, ou du moins amortis.

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

Bien que j'ai du mal à le tester

Magenta
la source
Je peux confirmer que ce bot fait ce qu'il est censé faire - et cela m'a aidé à trouver et à corriger un bogue dans le contrôleur
Blue